From b6f44e48506bba6b2234c9db11e7fa2c10cf7ac3 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 10 Jan 2023 23:04:34 -0800 Subject: [PATCH 001/196] modern lambda --- src/compiler/clvm.rs | 27 ++++---- src/compiler/codegen.rs | 5 +- src/compiler/evaluate.rs | 2 +- src/compiler/frontend.rs | 3 + src/compiler/lambda.rs | 118 +++++++++++++++++++++++++++++++++ src/compiler/mod.rs | 1 + src/tests/compiler/compiler.rs | 51 ++++++++++++++ 7 files changed, 192 insertions(+), 15 deletions(-) create mode 100644 src/compiler/lambda.rs diff --git a/src/compiler/clvm.rs b/src/compiler/clvm.rs index 956be4c5c..b502ba5f2 100644 --- a/src/compiler/clvm.rs +++ b/src/compiler/clvm.rs @@ -140,24 +140,25 @@ fn eval_args( loop { match sexp.borrow() { - SExp::Nil(_l) => { - return Ok(RunStep::Op( - head, - context_, - sexp.clone(), - Some(eval_list), - parent, - )); - } SExp::Cons(_l, a, b) => { eval_list.push(a.clone()); sexp = b.clone(); } _ => { - return Err(RunFailure::RunErr( - sexp.loc(), - format!("bad argument list {} {}", sexp_, context_), - )); + if !truthy(sexp.clone()) { + return Ok(RunStep::Op( + head, + context_, + sexp, + Some(eval_list), + parent, + )); + } else { + return Err(RunFailure::RunErr( + sexp.loc(), + format!("bad argument list {} {}", sexp_, context_), + )); + } } } } diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index c81cfd826..8f55dff50 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -569,7 +569,10 @@ pub fn generate_expr_code( } BodyForm::Mod(_, program) => { // A mod form yields the compiled code. - let code = codegen(allocator, runner, opts, program, &mut HashMap::new())?; + eprintln!("program {}", program.to_sexp()); + let without_env = opts.set_start_env(None).set_in_defun(false); + let code = codegen(allocator, runner, without_env, program, &mut HashMap::new())?; + eprintln!("code {}", code); Ok(CompiledCode( program.loc.clone(), Rc::new(SExp::Cons( diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 82d2eb5c8..151a29b64 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -80,7 +80,7 @@ fn make_operator1(l: &Srcloc, op: String, arg: Rc) -> BodyForm { ) } -fn make_operator2(l: &Srcloc, op: String, arg1: Rc, arg2: Rc) -> BodyForm { +pub fn make_operator2(l: &Srcloc, op: String, arg1: Rc, arg2: Rc) -> BodyForm { BodyForm::Call( l.clone(), vec![ diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index cfa41d1b5..94b8fa8b6 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -8,6 +8,7 @@ use crate::compiler::comptypes::{ list_to_cons, Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, DefconstData, DefmacData, DefunData, HelperForm, IncludeDesc, LetData, LetFormKind, ModAccum, }; +use crate::compiler::lambda::handle_lambda; use crate::compiler::preprocessor::preprocess; use crate::compiler::rename::rename_children_compileform; use crate::compiler::sexp::{enlist, SExp}; @@ -329,6 +330,8 @@ pub fn compile_bodyform( } else if *atom_name == "mod".as_bytes().to_vec() { let subparse = frontend(opts, &[body.clone()])?; Ok(BodyForm::Mod(op.loc(), subparse)) + } else if *atom_name == "lambda".as_bytes().to_vec() { + handle_lambda(opts, &v) } else { application() } diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs new file mode 100644 index 000000000..48a34a2a9 --- /dev/null +++ b/src/compiler/lambda.rs @@ -0,0 +1,118 @@ +use std::borrow::Borrow; +use std::rc::Rc; + +use crate::compiler::clvm::truthy; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts}; +use crate::compiler::evaluate::make_operator2; +use crate::compiler::frontend::{compile_bodyform, frontend}; +use crate::compiler::sexp::SExp; + +fn make_captures(opts: Rc, sexp: Rc) -> Result, CompileErr> { + if let SExp::Cons(l, f, r) = sexp.borrow() { + Ok(Rc::new(make_operator2( + &l, + "c".to_string(), + make_captures(opts.clone(), f.clone())?, + make_captures(opts, r.clone())? + ))) + } else if !truthy(sexp.clone()) { + Ok(Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc())))) + } else { + Ok(Rc::new(compile_bodyform(opts, sexp)?)) + } +} + +fn find_and_compose_captures(opts: Rc, sexp: &SExp) -> Result<(Rc, Option>), CompileErr> { + eprintln!("find_and_compose {}", sexp); + if let SExp::Cons(cl, l, r) = sexp { + if let SExp::Cons(_, head, rest) = l.borrow() { + if let SExp::Atom(_, name) = head.borrow() { + if name == b"&" { + let captures = make_captures(opts, rest.clone())?; + return Ok((Rc::new(SExp::Cons( + cl.clone(), + rest.clone(), + r.clone() + )), Some(captures))); + } + } + } + } + + Ok((Rc::new(sexp.clone()), None)) +} + +// +// Lambda +// +// (lambda ((= captures) arguments) +// (body) +// ) +// +// Yields: +// +// M = (mod ((captures) arguments) (body)) +// (qq (a (unquote M) (c (unquote captures) @))) +pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result { + let (args, captures) = + find_and_compose_captures(opts.clone(), &v[0])?; + + let mod_form_data = + Rc::new(SExp::Cons( + v[0].loc(), + Rc::new(SExp::atom_from_string(v[0].loc(), "mod")), + Rc::new(SExp::Cons( + args.loc(), + args.clone(), + Rc::new(SExp::Cons( + v[1].loc(), + Rc::new(v[1].clone()), + Rc::new(SExp::Nil(v[1].loc())) + )) + )) + )); + + if let Some(captures) = &captures { + // Requires captures + let subparse = frontend(opts, &[mod_form_data])?; + let module = BodyForm::Mod(v[0].loc(), subparse); + + eprintln!("captures {}", captures.to_sexp()); + let lambda_output = + BodyForm::Call( + v[0].loc(), + vec![ + Rc::new(BodyForm::Value(SExp::atom_from_string(v[0].loc(), "list"))), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![2]))), + Rc::new(make_operator2( + &v[0].loc(), + "c".to_string(), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![1]))), + Rc::new(module) + )), + Rc::new(BodyForm::Call( + v[0].loc(), + vec![ + Rc::new(BodyForm::Value(SExp::atom_from_string(v[0].loc(), "list"))), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![4]))), + Rc::new(make_operator2( + &v[0].loc(), + "c".to_string(), + Rc::new(BodyForm::Value(SExp::Atom(v[0].loc(), vec![1]))), + captures.clone() + )), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![1]))), + ] + )) + ] + ); + + eprintln!("lambda output {}", lambda_output.to_sexp()); + Ok(lambda_output) + } else { + // No captures + let subparse = frontend(opts, &[mod_form_data.clone()])?; + eprintln!("mod form {} subparse {}", mod_form_data, subparse.to_sexp()); + Ok(BodyForm::Mod(v[0].loc(), subparse)) + } +} diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 6fe0f9552..655641b1a 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -9,6 +9,7 @@ pub mod evaluate; pub mod frontend; pub mod gensym; mod inline; +mod lambda; mod optimize; pub mod preprocessor; pub mod prims; diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 9dbc42321..d4f2fbe62 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -42,6 +42,7 @@ fn run_string_maybe_opt( &mut HashMap::new(), ) .and_then(|x| { + eprintln!("run {}", x); run( &mut allocator, runner, @@ -1164,3 +1165,53 @@ fn test_inline_out_of_bounds_diagnostic() { assert!(false); } } + +#[test] +fn test_lambda_without_capture_from_function() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (defun FOO () (lambda (X Y) (+ X Y))) + (a (FOO) (list A B)) + )"} + .to_string(); + let res = run_string(&prog, &"(3 4)".to_string()).unwrap(); + assert_eq!(res.to_string(), "7"); +} + +#[test] +fn test_lambda_without_capture() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (a (lambda (X Y) (+ X Y)) (list A B)) + )"} + .to_string(); + let res = run_string(&prog, &"(3 4)".to_string()).unwrap(); + assert_eq!(res.to_string(), "7"); +} + +#[test] +fn test_lambda_with_capture_from_function() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (defun FOO (Z) (lambda ((& Z) X) (- X Z))) + (a (FOO A) (list B)) + )"} + .to_string(); + let res = run_string(&prog, &"(5 19)".to_string()).unwrap(); + assert_eq!(res.to_string(), "14"); +} + +#[test] +fn test_lambda_with_capture() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (a (lambda ((& A) Y) (- Y A)) (list B)) + )"} + .to_string(); + let res = run_string(&prog, &"(5 19)".to_string()).unwrap(); + assert_eq!(res.to_string(), "14"); +} From 48c78e026060af799e30468567464d6897b9801f Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 10 Jan 2023 23:14:13 -0800 Subject: [PATCH 002/196] fmt --- src/compiler/clvm.rs | 8 +--- src/compiler/lambda.rs | 95 +++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 55 deletions(-) diff --git a/src/compiler/clvm.rs b/src/compiler/clvm.rs index b502ba5f2..5064a86aa 100644 --- a/src/compiler/clvm.rs +++ b/src/compiler/clvm.rs @@ -146,13 +146,7 @@ fn eval_args( } _ => { if !truthy(sexp.clone()) { - return Ok(RunStep::Op( - head, - context_, - sexp, - Some(eval_list), - parent, - )); + return Ok(RunStep::Op(head, context_, sexp, Some(eval_list), parent)); } else { return Err(RunFailure::RunErr( sexp.loc(), diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 48a34a2a9..32ec1b72a 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -13,7 +13,7 @@ fn make_captures(opts: Rc, sexp: Rc) -> Result, sexp: Rc) -> Result, sexp: &SExp) -> Result<(Rc, Option>), CompileErr> { +fn find_and_compose_captures( + opts: Rc, + sexp: &SExp, +) -> Result<(Rc, Option>), CompileErr> { eprintln!("find_and_compose {}", sexp); if let SExp::Cons(cl, l, r) = sexp { if let SExp::Cons(_, head, rest) = l.borrow() { if let SExp::Atom(_, name) = head.borrow() { if name == b"&" { let captures = make_captures(opts, rest.clone())?; - return Ok((Rc::new(SExp::Cons( - cl.clone(), - rest.clone(), - r.clone() - )), Some(captures))); + return Ok(( + Rc::new(SExp::Cons(cl.clone(), rest.clone(), r.clone())), + Some(captures), + )); } } } @@ -54,23 +56,21 @@ fn find_and_compose_captures(opts: Rc, sexp: &SExp) -> Result< // M = (mod ((captures) arguments) (body)) // (qq (a (unquote M) (c (unquote captures) @))) pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result { - let (args, captures) = - find_and_compose_captures(opts.clone(), &v[0])?; + let (args, captures) = find_and_compose_captures(opts.clone(), &v[0])?; - let mod_form_data = + let mod_form_data = Rc::new(SExp::Cons( + v[0].loc(), + Rc::new(SExp::atom_from_string(v[0].loc(), "mod")), Rc::new(SExp::Cons( - v[0].loc(), - Rc::new(SExp::atom_from_string(v[0].loc(), "mod")), + args.loc(), + args.clone(), Rc::new(SExp::Cons( - args.loc(), - args.clone(), - Rc::new(SExp::Cons( - v[1].loc(), - Rc::new(v[1].clone()), - Rc::new(SExp::Nil(v[1].loc())) - )) - )) - )); + v[1].loc(), + Rc::new(v[1].clone()), + Rc::new(SExp::Nil(v[1].loc())), + )), + )), + )); if let Some(captures) = &captures { // Requires captures @@ -78,34 +78,33 @@ pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result Date: Tue, 10 Jan 2023 23:21:32 -0800 Subject: [PATCH 003/196] Add a test mixing mod and let --- src/tests/compiler/compiler.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index d4f2fbe62..3fc20c76c 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1215,3 +1215,21 @@ fn test_lambda_with_capture() { let res = run_string(&prog, &"(5 19)".to_string()).unwrap(); assert_eq!(res.to_string(), "14"); } + + +#[test] +fn test_lambda_in_let() { + let prog = indoc! {" +(mod (A B) + (include *standard-cl-21*) + (defun FOO (Z) + (let ((Q (* 2 Z))) + (lambda ((& Q) X) (- X Q)) + ) + ) + (a (FOO A) (list B)) + )"} + .to_string(); + let res = run_string(&prog, &"(5 19)".to_string()).unwrap(); + assert_eq!(res.to_string(), "9"); +} From 9620d5c7562ba561e5eacecf17d5b0ded649de69 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 10 Jan 2023 23:32:25 -0800 Subject: [PATCH 004/196] Add practical map example --- src/compiler/codegen.rs | 2 -- src/compiler/lambda.rs | 4 ---- src/tests/compiler/compiler.rs | 26 +++++++++++++++++++++++++- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 8f55dff50..edbd96b02 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -569,10 +569,8 @@ pub fn generate_expr_code( } BodyForm::Mod(_, program) => { // A mod form yields the compiled code. - eprintln!("program {}", program.to_sexp()); let without_env = opts.set_start_env(None).set_in_defun(false); let code = codegen(allocator, runner, without_env, program, &mut HashMap::new())?; - eprintln!("code {}", code); Ok(CompiledCode( program.loc.clone(), Rc::new(SExp::Cons( diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 32ec1b72a..c10ecd9eb 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -26,7 +26,6 @@ fn find_and_compose_captures( opts: Rc, sexp: &SExp, ) -> Result<(Rc, Option>), CompileErr> { - eprintln!("find_and_compose {}", sexp); if let SExp::Cons(cl, l, r) = sexp { if let SExp::Cons(_, head, rest) = l.borrow() { if let SExp::Atom(_, name) = head.borrow() { @@ -77,7 +76,6 @@ pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result, v: &[SExp]) -> Result Date: Tue, 10 Jan 2023 23:32:49 -0800 Subject: [PATCH 005/196] fmt --- src/tests/compiler/compiler.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 70c7151ed..6d637b36e 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1215,7 +1215,6 @@ fn test_lambda_with_capture() { assert_eq!(res.to_string(), "14"); } - #[test] fn test_lambda_in_let() { let prog = indoc! {" From bfad07ebd6e8b7ad51b79ab3bf318cedbadfb1a9 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 10 Jan 2023 23:35:49 -0800 Subject: [PATCH 006/196] clippy --- src/compiler/lambda.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index c10ecd9eb..303ebd502 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -10,7 +10,7 @@ use crate::compiler::sexp::SExp; fn make_captures(opts: Rc, sexp: Rc) -> Result, CompileErr> { if let SExp::Cons(l, f, r) = sexp.borrow() { Ok(Rc::new(make_operator2( - &l, + l, "c".to_string(), make_captures(opts.clone(), f.clone())?, make_captures(opts, r.clone())?, @@ -107,7 +107,7 @@ pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result Date: Tue, 10 Jan 2023 23:48:01 -0800 Subject: [PATCH 007/196] More tests --- src/tests/compiler/compiler.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 6d637b36e..e8faa1e9c 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1256,3 +1256,30 @@ fn test_lambda_in_map() { let res = run_string(&prog, &"(5 (1 2 3 4))".to_string()).unwrap(); assert_eq!(res.to_string(), "(6 7 8 9)"); } + +#[test] +fn test_lambda_in_map_with_let_surrounding() { + let prog = indoc! {" +(mod (add-number L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (map + (let ((A (* add-number 2))) + (lambda ((& A) number) (+ A number)) + ) + L + ) + ) +"} + .to_string(); + let res = run_string(&prog, &"(5 (1 2 3 4))".to_string()).unwrap(); + assert_eq!(res.to_string(), "(11 12 13 14)"); +} From 469d25055d39225ca2c9794ce0ce108ca708f1c9 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 13 Jan 2023 13:49:07 -0800 Subject: [PATCH 008/196] Working lambdas with env capture --- src/compiler/codegen.rs | 30 ++++++- src/compiler/comptypes.rs | 19 +++-- src/compiler/evaluate.rs | 4 +- src/compiler/frontend.rs | 22 ++++- src/compiler/lambda.rs | 141 ++++++++++++++++++++------------- src/compiler/rename.rs | 4 +- src/tests/compiler/compiler.rs | 57 +++++++++++++ 7 files changed, 206 insertions(+), 71 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index edbd96b02..128aff286 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -21,6 +21,7 @@ use crate::compiler::debug::{build_swap_table_mut, relabel}; use crate::compiler::frontend::compile_bodyform; use crate::compiler::gensym::gensym; use crate::compiler::inline::{replace_in_inline, synthesize_args}; +use crate::compiler::lambda::compose_constant_function_env; use crate::compiler::optimize::optimize_expr; use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; @@ -567,7 +568,34 @@ pub fn generate_expr_code( compile_call(allocator, runner, l.clone(), opts, compiler, list.to_vec()) } } - BodyForm::Mod(_, program) => { + BodyForm::Mod(_, true, program) => { + let parent_env = compose_constant_function_env(compiler)?; + let env = Rc::new(SExp::Cons( + program.args.loc(), + parent_env, + program.args.clone(), + )); + let opts_with_env = opts + .set_start_env(Some(env)) + .set_in_defun(true) + .set_compiler(compiler.clone()); + let code = codegen( + allocator, + runner, + opts_with_env, + program, + &mut HashMap::new(), + )?; + Ok(CompiledCode( + program.loc.clone(), + Rc::new(SExp::Cons( + program.loc.clone(), + Rc::new(SExp::Atom(program.loc.clone(), vec![1])), + Rc::new(code), + )), + )) + } + BodyForm::Mod(_, false, program) => { // A mod form yields the compiled code. let without_env = opts.set_start_env(None).set_in_defun(false); let code = codegen(allocator, runner, without_env, program, &mut HashMap::new())?; diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index cbe4adb4c..e698b315a 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -85,7 +85,7 @@ pub enum BodyForm { Quoted(SExp), Value(SExp), Call(Srcloc, Vec>), - Mod(Srcloc, CompileForm), + Mod(Srcloc, bool, CompileForm), } #[derive(Clone, Debug)] @@ -213,6 +213,7 @@ pub struct ModAccum { pub loc: Srcloc, pub includes: Vec, pub helpers: Vec, + pub left_capture: bool, pub exp_form: Option, } @@ -222,6 +223,7 @@ impl ModAccum { loc: self.loc.clone(), includes: self.includes.clone(), helpers: self.helpers.clone(), + left_capture: self.left_capture, exp_form: Some(c.clone()), } } @@ -233,6 +235,7 @@ impl ModAccum { loc: self.loc.clone(), includes: new_includes, helpers: self.helpers.clone(), + left_capture: self.left_capture, exp_form: self.exp_form.clone(), } } @@ -245,15 +248,17 @@ impl ModAccum { loc: self.loc.clone(), includes: self.includes.clone(), helpers: hs, + left_capture: self.left_capture, exp_form: self.exp_form.clone(), } } - pub fn new(loc: Srcloc) -> ModAccum { + pub fn new(loc: Srcloc, left_capture: bool) -> ModAccum { ModAccum { loc, includes: Vec::new(), helpers: Vec::new(), + left_capture, exp_form: None, } } @@ -384,7 +389,7 @@ impl BodyForm { BodyForm::Quoted(a) => a.loc(), BodyForm::Call(loc, _) => loc.clone(), BodyForm::Value(a) => a.loc(), - BodyForm::Mod(kl, program) => kl.ext(&program.loc), + BodyForm::Mod(kl, _, program) => kl.ext(&program.loc), } } @@ -424,9 +429,13 @@ impl BodyForm { let converted: Vec> = exprs.iter().map(|x| x.to_sexp()).collect(); Rc::new(list_to_cons(loc.clone(), &converted)) } - BodyForm::Mod(loc, program) => Rc::new(SExp::Cons( + BodyForm::Mod(loc, left_env, program) => Rc::new(SExp::Cons( loc.clone(), - Rc::new(SExp::Atom(loc.clone(), b"mod".to_vec())), + if *left_env { + Rc::new(SExp::Atom(loc.clone(), b"mod+".to_vec())) + } else { + Rc::new(SExp::Atom(loc.clone(), b"mod".to_vec())) + }, program.to_sexp(), )), } diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 151a29b64..36a233956 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -70,7 +70,7 @@ pub fn is_primitive(expr: &BodyForm) -> bool { ) } -fn make_operator1(l: &Srcloc, op: String, arg: Rc) -> BodyForm { +pub fn make_operator1(l: &Srcloc, op: String, arg: Rc) -> BodyForm { BodyForm::Call( l.clone(), vec![ @@ -1062,7 +1062,7 @@ impl Evaluator { )), } } - BodyForm::Mod(_, program) => { + BodyForm::Mod(_, _, program) => { // A mod form yields the compiled code. let code = codegen( allocator, diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 94b8fa8b6..481db1033 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -64,7 +64,17 @@ fn collect_used_names_bodyform(body: &BodyForm) -> Vec> { } result } - BodyForm::Mod(_, _) => vec![], + BodyForm::Mod(_, false, _) => vec![], + BodyForm::Mod(_, true, form) => { + let mut result = Vec::new(); + for h in form.helpers.iter() { + let mut helper_uses = collect_used_names_helperform(h); + result.append(&mut helper_uses); + } + let mut body_uses = collect_used_names_bodyform(form.exp.borrow()); + result.append(&mut body_uses); + result + } } } @@ -329,7 +339,10 @@ pub fn compile_bodyform( qq_to_expression(opts, Rc::new(quote_body)) } else if *atom_name == "mod".as_bytes().to_vec() { let subparse = frontend(opts, &[body.clone()])?; - Ok(BodyForm::Mod(op.loc(), subparse)) + Ok(BodyForm::Mod(op.loc(), false, subparse)) + } else if *atom_name == "mod+".as_bytes().to_vec() { + let subparse = frontend(opts, &[body.clone()])?; + Ok(BodyForm::Mod(op.loc(), true, subparse)) } else if *atom_name == "lambda".as_bytes().to_vec() { handle_lambda(opts, &v) } else { @@ -681,14 +694,15 @@ fn frontend_start( )); } - if *mod_atom == "mod".as_bytes().to_vec() { + let is_capture_mod = *mod_atom == b"mod+"; + if is_capture_mod || *mod_atom == b"mod" { let args = Rc::new(x[1].clone()); let body_vec = x.iter().skip(2).map(|s| Rc::new(s.clone())).collect(); let body = Rc::new(enlist(pre_forms[0].loc(), body_vec)); let ls = preprocess(opts.clone(), includes, body)?; return compile_mod_( - &ModAccum::new(l.clone()), + &ModAccum::new(l.clone(), is_capture_mod), opts.clone(), args, Rc::new(list_to_cons(l, &ls)), diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 303ebd502..9cf683a02 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -1,11 +1,20 @@ use std::borrow::Borrow; use std::rc::Rc; +use num_bigint::ToBigInt; + use crate::compiler::clvm::truthy; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts}; -use crate::compiler::evaluate::make_operator2; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, PrimaryCodegen}; +use crate::compiler::evaluate::{make_operator1, make_operator2}; use crate::compiler::frontend::{compile_bodyform, frontend}; -use crate::compiler::sexp::SExp; +use crate::compiler::sexp::{enlist, SExp}; + +pub fn compose_constant_function_env(compiler: &PrimaryCodegen) -> Result, CompileErr> { + match compiler.env.borrow() { + SExp::Cons(_, left, _) => Ok(left.clone()), + _ => Ok(Rc::new(SExp::Nil(compiler.env.loc()))), + } +} fn make_captures(opts: Rc, sexp: Rc) -> Result, CompileErr> { if let SExp::Cons(l, f, r) = sexp.borrow() { @@ -25,22 +34,26 @@ fn make_captures(opts: Rc, sexp: Rc) -> Result, sexp: &SExp, -) -> Result<(Rc, Option>), CompileErr> { - if let SExp::Cons(cl, l, r) = sexp { +) -> Result<(Rc, Rc), CompileErr> { + let mut args = Rc::new(sexp.clone()); + let mut capture_args = Rc::new(SExp::Nil(sexp.loc())); + let mut captures = Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc()))); + if let SExp::Cons(_, l, r) = sexp { if let SExp::Cons(_, head, rest) = l.borrow() { if let SExp::Atom(_, name) = head.borrow() { if name == b"&" { - let captures = make_captures(opts, rest.clone())?; - return Ok(( - Rc::new(SExp::Cons(cl.clone(), rest.clone(), r.clone())), - Some(captures), - )); + args = r.clone(); + capture_args = rest.clone(); + captures = make_captures(opts, rest.clone())?; } } } } - Ok((Rc::new(sexp.clone()), None)) + Ok(( + Rc::new(SExp::Cons(sexp.loc(), capture_args.clone(), args.clone())), + captures, + )) } // @@ -55,59 +68,73 @@ fn find_and_compose_captures( // M = (mod ((captures) arguments) (body)) // (qq (a (unquote M) (c (unquote captures) @))) pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result { + if v.len() < 2 { + return Err(CompileErr( + v[0].loc(), + "Must provide at least arguments and body to lambda".to_string(), + )); + } + let (args, captures) = find_and_compose_captures(opts.clone(), &v[0])?; + let rolled_elements_vec: Vec> = v.iter().skip(1).map(|x| Rc::new(x.clone())).collect(); + let body_list = enlist(v[0].loc(), rolled_elements_vec); let mod_form_data = Rc::new(SExp::Cons( v[0].loc(), - Rc::new(SExp::atom_from_string(v[0].loc(), "mod")), - Rc::new(SExp::Cons( - args.loc(), - args.clone(), - Rc::new(SExp::Cons( - v[1].loc(), - Rc::new(v[1].clone()), - Rc::new(SExp::Nil(v[1].loc())), - )), - )), + Rc::new(SExp::atom_from_string(v[0].loc(), "mod+")), + Rc::new(SExp::Cons(args.loc(), args.clone(), Rc::new(body_list))), )); - if let Some(captures) = &captures { - // Requires captures - let subparse = frontend(opts, &[mod_form_data])?; - let module = BodyForm::Mod(v[0].loc(), subparse); + // Requires captures + let subparse = frontend(opts, &[mod_form_data])?; + let module = BodyForm::Mod(v[0].loc(), true, subparse); - let lambda_output = BodyForm::Call( - v[0].loc(), - vec![ - Rc::new(BodyForm::Value(SExp::atom_from_string(v[0].loc(), "list"))), - Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![2]))), - Rc::new(make_operator2( - &v[0].loc(), - "c".to_string(), - Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![1]))), - Rc::new(module), - )), - Rc::new(BodyForm::Call( - v[0].loc(), - vec![ - Rc::new(BodyForm::Value(SExp::atom_from_string(v[0].loc(), "list"))), - Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![4]))), - Rc::new(make_operator2( + let lambda_output = BodyForm::Call( + v[0].loc(), + vec![ + Rc::new(BodyForm::Value(SExp::atom_from_string(v[0].loc(), "list"))), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![2]))), + Rc::new(make_operator2( + &v[0].loc(), + "c".to_string(), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![1]))), + Rc::new(module), + )), + Rc::new(BodyForm::Call( + v[0].loc(), + vec![ + Rc::new(BodyForm::Value(SExp::atom_from_string(v[0].loc(), "list"))), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![4]))), + Rc::new(make_operator2( + &v[0].loc(), + "c".to_string(), + Rc::new(BodyForm::Value(SExp::Atom(v[0].loc(), vec![1]))), + Rc::new(make_operator1( &v[0].loc(), - "c".to_string(), - Rc::new(BodyForm::Value(SExp::Atom(v[0].loc(), vec![1]))), - captures.clone(), + "@".to_string(), + Rc::new(BodyForm::Value(SExp::Integer( + v[0].loc(), + 2_u32.to_bigint().unwrap(), + ))), )), - Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![1]))), - ], - )), - ], - ); - - Ok(lambda_output) - } else { - // No captures - let subparse = frontend(opts, &[mod_form_data])?; - Ok(BodyForm::Mod(v[0].loc(), subparse)) - } + )), + Rc::new(BodyForm::Call( + v[0].loc(), + vec![ + Rc::new(BodyForm::Value(SExp::atom_from_string(v[0].loc(), "list"))), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![4]))), + Rc::new(make_operator2( + &v[0].loc(), + "c".to_string(), + Rc::new(BodyForm::Value(SExp::Atom(v[0].loc(), vec![1]))), + captures.clone(), + )), + Rc::new(BodyForm::Quoted(SExp::Atom(v[0].loc(), vec![1]))), + ], + )), + ], + )), + ], + ); + Ok(lambda_output) } diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index c744d5cb8..0e347459d 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -167,7 +167,7 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B BodyForm::Call(l.clone(), new_vs) } - BodyForm::Mod(l, prog) => BodyForm::Mod(l.clone(), prog.clone()), + BodyForm::Mod(l, left_env, prog) => BodyForm::Mod(l.clone(), *left_env, prog.clone()), } } @@ -254,7 +254,7 @@ fn rename_args_bodyform(b: &BodyForm) -> BodyForm { .collect(); BodyForm::Call(l.clone(), new_vs) } - BodyForm::Mod(l, program) => BodyForm::Mod(l.clone(), program.clone()), + BodyForm::Mod(l, left_env, program) => BodyForm::Mod(l.clone(), *left_env, program.clone()), } } diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index e8faa1e9c..de496b300 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1283,3 +1283,60 @@ fn test_lambda_in_map_with_let_surrounding() { let res = run_string(&prog, &"(5 (1 2 3 4))".to_string()).unwrap(); assert_eq!(res.to_string(), "(11 12 13 14)"); } + +#[test] +fn test_map_with_lambda_function_from_env_and_bindings() { + let prog = indoc! {" + (mod (add-number L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (defun add-twice (X Y) (+ (* 2 X) Y)) + + (map + (lambda ((& add-number) number) (add-twice add-number number)) + L + ) + )"} + .to_string(); + let res = run_string(&prog, &"(5 (1 2 3 4))".to_string()).unwrap(); + assert_eq!(res.to_string(), "(11 12 13 14)"); +} + +#[test] +fn test_map_with_lambda_function_from_env_no_bindings() { + let prog = indoc! {" + (mod (L) + + (include *standard-cl-21*) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (defun sum-list (L) + (if L + (+ (f L) (sum-list (r L))) + () + ) + ) + + (map + (lambda (lst) (sum-list lst)) + L + ) + )"} + .to_string(); + let res = run_string(&prog, &"(((5 10 15) (2 4 8) (3 6 9)))".to_string()).unwrap(); + assert_eq!(res.to_string(), "(30 14 18)"); +} From 2da8ec45fa669a25ac1275c3d424a4d2e028461b Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 17 Jan 2023 14:42:47 -0800 Subject: [PATCH 009/196] Cleanup lambda generation a lot, ensure macros work downstream of mod+ --- src/compiler/codegen.rs | 1 + src/compiler/lambda.rs | 131 ++++++++++++++++++++++----------- src/tests/compiler/compiler.rs | 48 ++++++++++++ 3 files changed, 139 insertions(+), 41 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 128aff286..03742b2c6 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -1038,6 +1038,7 @@ fn start_codegen( .set_compiler(use_compiler.clone()) .set_in_defun(false) .set_stdenv(false) + .set_start_env(None) .set_frontend_opt(false); updated_opts diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 9cf683a02..52e8458f9 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -8,6 +8,7 @@ use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, PrimaryCode use crate::compiler::evaluate::{make_operator1, make_operator2}; use crate::compiler::frontend::{compile_bodyform, frontend}; use crate::compiler::sexp::{enlist, SExp}; +use crate::compiler::srcloc::Srcloc; pub fn compose_constant_function_env(compiler: &PrimaryCodegen) -> Result, CompileErr> { match compiler.env.borrow() { @@ -56,6 +57,40 @@ fn find_and_compose_captures( )) } +fn make_call( + loc: Srcloc, + head: &str, + args: &[BodyForm] +) -> BodyForm { + let mut use_vec: Vec> = args.iter().cloned().map(Rc::new).collect(); + use_vec.insert(0, Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), head)))); + BodyForm::Call(loc, use_vec) +} + +fn make_operator( + loc: Srcloc, + op: u8, + arg1: Rc, + arg2: Rc +) -> BodyForm { + BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc, vec![op]))), + arg1, + arg2 + ] + ) +} + +fn make_cons( + loc: Srcloc, + arg1: Rc, + arg2: Rc +) -> BodyForm { + make_operator(loc, 4, arg1, arg2) +} + // // Lambda // @@ -66,7 +101,11 @@ fn find_and_compose_captures( // Yields: // // M = (mod ((captures) arguments) (body)) -// (qq (a (unquote M) (c (unquote captures) @))) +// (list 2 +// (c 1 (mod ((captures) arguments) body)) +// (list 4 (c 1 (@ 2)) (list 4 (c 1 compose_captures) @)) +// ) +// pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result { if v.len() < 2 { return Err(CompileErr( @@ -79,6 +118,8 @@ pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result> = v.iter().skip(1).map(|x| Rc::new(x.clone())).collect(); let body_list = enlist(v[0].loc(), rolled_elements_vec); + + // Make the mod form let mod_form_data = Rc::new(SExp::Cons( v[0].loc(), Rc::new(SExp::atom_from_string(v[0].loc(), "mod+")), @@ -89,51 +130,59 @@ pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result Date: Tue, 17 Jan 2023 14:48:38 -0800 Subject: [PATCH 010/196] fmt + clippy --- src/compiler/lambda.rs | 54 +++++++++++------------------------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 52e8458f9..9e2fd4550 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -52,42 +52,32 @@ fn find_and_compose_captures( } Ok(( - Rc::new(SExp::Cons(sexp.loc(), capture_args.clone(), args.clone())), + Rc::new(SExp::Cons(sexp.loc(), capture_args, args)), captures, )) } -fn make_call( - loc: Srcloc, - head: &str, - args: &[BodyForm] -) -> BodyForm { +fn make_call(loc: Srcloc, head: &str, args: &[BodyForm]) -> BodyForm { let mut use_vec: Vec> = args.iter().cloned().map(Rc::new).collect(); - use_vec.insert(0, Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), head)))); + use_vec.insert( + 0, + Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), head))), + ); BodyForm::Call(loc, use_vec) } -fn make_operator( - loc: Srcloc, - op: u8, - arg1: Rc, - arg2: Rc -) -> BodyForm { +fn make_operator(loc: Srcloc, op: u8, arg1: Rc, arg2: Rc) -> BodyForm { BodyForm::Call( loc.clone(), vec![ Rc::new(BodyForm::Value(SExp::Atom(loc, vec![op]))), arg1, - arg2 - ] + arg2, + ], ) } -fn make_cons( - loc: Srcloc, - arg1: Rc, - arg2: Rc -) -> BodyForm { +fn make_cons(loc: Srcloc, arg1: Rc, arg2: Rc) -> BodyForm { make_operator(loc, 4, arg1, arg2) } @@ -145,16 +135,8 @@ pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result, v: &[SExp]) -> Result Date: Tue, 7 Feb 2023 16:24:36 -0800 Subject: [PATCH 011/196] Added extra verification --- src/compiler/lambda.rs | 1 + src/tests/classic/run.rs | 33 +++++++++++++++++++++++++++++++++ src/tests/compiler/compiler.rs | 23 +++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 9e2fd4550..5b21a95fa 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -105,6 +105,7 @@ pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result> = v.iter().skip(1).map(|x| Rc::new(x.clone())).collect(); let body_list = enlist(v[0].loc(), rolled_elements_vec); diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 178144dd5..340465bce 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -807,3 +807,36 @@ fn test_modern_sets_source_file_in_symbols() { Some("resources/tests/steprun/fact.cl".to_string()) ); } + +// Test that leaving off the lambda captures causes bare words for the +// requested values to find their way into the output and that having +// the capture catches it. This shows that uses of uncaptured words +// are unencumbered. +#[test] +fn test_lambda_without_capture_reproduces_bare_word_in_output() { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/rps-referee-uncaptured.clsp".to_string(), + ]) + .trim() + .to_string(); + assert!(compiled.contains("AMOUNT")); + assert!(compiled.contains("new_puzzle_hash")); +} + +// Test that having a lambda capture captures all the associated words. +#[test] +fn test_lambda_with_capture_defines_word() { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/rps-referee.clsp".to_string(), + ]) + .trim() + .to_string(); + assert!(!compiled.contains("AMOUNT")); + assert!(!compiled.contains("new_puzzle_hash")); +} diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 5b6b15b32..6cd6cfcee 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1390,3 +1390,26 @@ fn test_lambda_using_macro() { let res = run_string(&prog, &"(1 (10 20 30))".to_string()).unwrap(); assert_eq!(res.to_string(), "((1 10) (1 20) (1 30))"); } + +#[test] +fn test_lambda_reduce() { + let prog = indoc! {" + (mod (LST) + (include *standard-cl-21*) + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) + + (let + ((capture 100)) + (reduce (lambda ((& capture) (X Y) ACC) (+ (* X Y) ACC capture)) LST 0) + ) + ) + "} + .to_string(); + let res = run_string(&prog, &"(((2 3) (4 9)))".to_string()).unwrap(); + assert_eq!(res.to_string(), "242"); +} From 980cf57bea9f0f815f939a2bf88b76f893dda4f7 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 7 Feb 2023 16:48:16 -0800 Subject: [PATCH 012/196] missing + fmt --- resources/tests/rps-referee-uncaptured.clsp | 29 +++++++++++++++++++++ resources/tests/rps-referee.clsp | 29 +++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 resources/tests/rps-referee-uncaptured.clsp create mode 100644 resources/tests/rps-referee.clsp diff --git a/resources/tests/rps-referee-uncaptured.clsp b/resources/tests/rps-referee-uncaptured.clsp new file mode 100644 index 000000000..1dcf38858 --- /dev/null +++ b/resources/tests/rps-referee-uncaptured.clsp @@ -0,0 +1,29 @@ +(mod ((VALIDATION_PROGRAM_HASH AMOUNT) action . args) + + (include *standard-cl-21*) + + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) + + (let + ((new_puzzle_hash 38911) + ) + (reduce + (lambda ((@ condition (condname arg1 arg2)) agg) + (if agg + 1 + (if (= condname CREATE_COIN) + (logand (= arg1 new_puzzle_hash) (= arg2 AMOUNT)) + 0 + ) + ) + ) + conditions + 0 + ) + ) + ) diff --git a/resources/tests/rps-referee.clsp b/resources/tests/rps-referee.clsp new file mode 100644 index 000000000..38741b09f --- /dev/null +++ b/resources/tests/rps-referee.clsp @@ -0,0 +1,29 @@ +(mod ((VALIDATION_PROGRAM_HASH AMOUNT) action . args) + + (include *standard-cl-21*) + + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) + + (let + ((new_puzzle_hash 38911) + ) + (reduce + (lambda ((& AMOUNT new_puzzle_hash) (@ condition (condname arg1 arg2)) agg) + (if agg + 1 + (if (= condname CREATE_COIN) + (logand (= arg1 new_puzzle_hash) (= arg2 AMOUNT)) + 0 + ) + ) + ) + conditions + 0 + ) + ) + ) From f5378f7536b8aee8a818a408572afe9d1c75f756 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 27 Feb 2023 16:59:32 -0800 Subject: [PATCH 013/196] Refine lambda and add more tests of the evaluator now that we rely on it to handle the sugared lambda bodyform --- src/compiler/codegen.rs | 17 +++- src/compiler/comptypes.rs | 90 +++++++++++++++++- src/compiler/evaluate.rs | 161 ++++++++++++++++++++++++++++++++- src/compiler/frontend.rs | 26 +++--- src/compiler/inline.rs | 19 +++- src/compiler/lambda.rs | 91 +++++++++++-------- src/compiler/rename.rs | 49 ++++++++-- src/tests/classic/run.rs | 2 +- src/tests/compiler/evaluate.rs | 32 +++++++ src/tests/compiler/repl.rs | 26 +++++- 10 files changed, 441 insertions(+), 72 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 2fefd38c8..eeebb8896 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -22,7 +22,7 @@ use crate::compiler::evaluate::{Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::frontend::compile_bodyform; use crate::compiler::gensym::gensym; use crate::compiler::inline::{replace_in_inline, synthesize_args}; -use crate::compiler::lambda::compose_constant_function_env; +use crate::compiler::lambda::{compose_constant_function_env, lambda_codegen}; use crate::compiler::optimize::optimize_expr; use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; @@ -585,7 +585,7 @@ pub fn generate_expr_code( allocator, runner, opts_with_env, - program, + &program, &mut HashMap::new(), )?; Ok(CompiledCode( @@ -610,6 +610,19 @@ pub fn generate_expr_code( )), )) } + BodyForm::Lambda(ldata) => { + let desugared_lambda_callsite = lambda_codegen( + opts.clone(), &ldata + )?; + let result = generate_expr_code( + allocator, + runner, + opts, + compiler, + Rc::new(desugared_lambda_callsite) + )?; + Ok(result) + } _ => Err(CompileErr( expr.loc(), format!("don't know how to compile {}", expr.to_sexp()), diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 5eade8096..f0e06b455 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -1,3 +1,4 @@ +use std::borrow::Borrow; use std::collections::HashMap; use std::collections::HashSet; use std::rc::Rc; @@ -7,10 +8,18 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{Bytes, BytesFromType}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::sha256tree; +use crate::compiler::clvm::{sha256tree, truthy}; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; +// Note: only used in tests, not normally dependencies. +#[cfg(test)] +use crate::compiler::compiler::DefaultCompilerOpts; +#[cfg(test)] +use crate::compiler::frontend::compile_bodyform; +#[cfg(test)] +use crate::compiler::sexp::parse_sexp; + #[derive(Clone, Debug)] pub struct CompileErr(pub Srcloc, pub String); @@ -85,6 +94,16 @@ pub struct LetData { pub body: Rc, } +#[derive(Clone, Debug)] +pub struct LambdaData { + pub loc: Srcloc, + pub kw: Option, + pub capture_args: Rc, + pub captures: Rc, + pub args: Rc, + pub body: Rc, +} + #[derive(Clone, Debug)] pub enum BodyForm { Let(LetFormKind, LetData), @@ -92,6 +111,7 @@ pub enum BodyForm { Value(SExp), Call(Srcloc, Vec>), Mod(Srcloc, bool, CompileForm), + Lambda(LambdaData), } #[derive(Clone, Debug)] @@ -406,6 +426,45 @@ impl HelperForm { } } +fn compose_lambda_serialized_form(ldata: &LambdaData) -> Rc { + let lambda_kw = Rc::new(SExp::Atom(ldata.loc.clone(), b"lambda".to_vec())); + let amp_kw = Rc::new(SExp::Atom(ldata.loc.clone(), b"&".to_vec())); + let arguments = + if truthy(ldata.capture_args.clone()) { + Rc::new(SExp::Cons( + ldata.loc.clone(), + Rc::new(SExp::Cons( + ldata.loc.clone(), + amp_kw, + ldata.capture_args.clone() + )), + ldata.args.clone() + )) + } else { + ldata.args.clone() + }; + let rest_of_body = + if let SExp::Cons(_, _, after_kw) = ldata.body.to_sexp().borrow() { + if let SExp::Cons(_, _, after_args) = after_kw.borrow() { + after_args.clone() + } else { + Rc::new(SExp::Nil(ldata.loc.clone())) + } + } else { + Rc::new(SExp::Nil(ldata.loc.clone())) + }; + + Rc::new(SExp::Cons( + ldata.loc.clone(), + lambda_kw, + Rc::new(SExp::Cons( + ldata.loc.clone(), + arguments, + rest_of_body + )) + )) +} + impl BodyForm { pub fn loc(&self) -> Srcloc { match self { @@ -414,6 +473,7 @@ impl BodyForm { BodyForm::Call(loc, _) => loc.clone(), BodyForm::Value(a) => a.loc(), BodyForm::Mod(kl, _, program) => kl.ext(&program.loc), + BodyForm::Lambda(ldata) => ldata.loc.ext(&ldata.body.loc()), } } @@ -462,10 +522,38 @@ impl BodyForm { }, program.to_sexp(), )), + BodyForm::Lambda(ldata) => { + let lambda = Rc::new(SExp::Atom(ldata.loc.clone(), b"lambda".to_vec())); + compose_lambda_serialized_form(&ldata) + } } } } +// Note: in cfg(test), this will not be part of the finished binary. +// Also: not a test in itself, just named test so for at least some readers, +// its association with test infrastructure will be apparent. +#[cfg(test)] +fn test_parse_bodyform_to_frontend(bf: &str) { + let name = "*test*"; + let loc = Srcloc::start(name); + let opts = Rc::new(DefaultCompilerOpts::new(name)); + let parsed = parse_sexp(loc, bf.bytes()).expect("should parse"); + let bodyform = compile_bodyform(opts, parsed[0].clone()).expect("should compile"); + assert_eq!(bodyform.to_sexp(), parsed[0]); +} + +// Inline unit tests for sexp serialization. +#[test] +fn test_mod_serialize_regular_mod() { + test_parse_bodyform_to_frontend("(mod (X) (+ X 1))"); +} + +#[test] +fn test_mod_serialize_simple_lambda() { + test_parse_bodyform_to_frontend("(lambda (X) (+ X 1))"); +} + impl Binding { pub fn to_sexp(&self) -> Rc { Rc::new(SExp::Cons( diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index e9cce46fb..3bff67475 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -13,7 +13,7 @@ use crate::compiler::clvm::run; use crate::compiler::codegen::codegen; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ - Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, LetData, LetFormKind, + Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, LambdaData, LetData, LetFormKind, }; use crate::compiler::frontend::frontend; use crate::compiler::runtypes::RunFailure; @@ -62,6 +62,12 @@ impl<'info> VisitedInfoAccess for VisitedMarker<'info, VisitedInfo> { } } +pub struct LambdaApply { + lambda: LambdaData, + body: Rc, + env: Rc +} + // Frontend evaluator based on my fuzzer representation and direct interpreter of // that. #[derive(Debug)] @@ -643,11 +649,105 @@ impl<'info> Evaluator { } } + fn is_lambda_apply( + &self, + allocator: &mut Allocator, + visited_: &'info mut VisitedMarker<'_, VisitedInfo>, + prog_args: Rc, + env: &HashMap, Rc>, + parts: &[Rc], + only_inline: bool + ) -> Result, CompileErr> { + if parts.len() == 3 && is_apply_atom(parts[0].to_sexp()) { + let mut visited = VisitedMarker::again(parts[0].loc(), visited_)?; + let evaluated_prog = + self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args.clone(), + env, + parts[1].clone(), + only_inline + )?; + let evaluated_env = + self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args.clone(), + env, + parts[2].clone(), + only_inline + )?; + if let BodyForm::Lambda(ldata) = evaluated_prog.borrow() { + if let BodyForm::Mod(_, _, cf) = ldata.body.borrow() { + return Ok(Some(LambdaApply { + lambda: ldata.clone(), + body: cf.exp.clone(), + env: evaluated_env.clone() + })); + } + } + } + + Ok(None) + } + + fn do_lambda_apply( + &self, + allocator: &mut Allocator, + visited: &mut VisitedMarker<'info, VisitedInfo>, + prog_args: Rc, + env: &HashMap, Rc>, + lapply: &LambdaApply, + only_inline: bool, + ) -> Result, CompileErr> { + let mut lambda_env = env.clone(); + // Finish eta-expansion. + + // We're carrying an enriched environment which we can use to enrich + // the env map at this time. Once we do that we can expand the body + // fully because we're carring the info that goes with the primary + // arguments. + // + // Generate the enriched environment. + let reified_captures = self.shrink_bodyform_visited( + allocator, + visited, + prog_args.clone(), + env, + lapply.lambda.captures.clone(), + only_inline + )?; + let formed_caps = ArgInputs::Whole(reified_captures.clone()); + create_argument_captures( + &mut lambda_env, + &formed_caps, + lapply.lambda.capture_args.clone() + )?; + + // Create captures with the actual parameters. + let formed_args = ArgInputs::Whole(lapply.env.clone()); + create_argument_captures( + &mut lambda_env, + &formed_args, + lapply.lambda.args.clone() + )?; + + self.shrink_bodyform_visited( + allocator, + visited, + prog_args, + &lambda_env, + lapply.body.clone(), + only_inline + ) + } + #[allow(clippy::too_many_arguments)] fn invoke_primitive( &self, allocator: &mut Allocator, - visited: &mut VisitedMarker<'info, VisitedInfo>, + visited_: &'info mut VisitedMarker<'_, VisitedInfo>, l: Srcloc, call_name: &[u8], parts: &[Rc], @@ -659,6 +759,7 @@ impl<'info> Evaluator { ) -> Result, CompileErr> { let mut all_primitive = true; let mut target_vec: Vec> = parts.to_owned(); + let mut visited = VisitedMarker::again(body.loc(), visited_)?; if call_name == "@".as_bytes() { // Synthesize the environment for this function @@ -698,7 +799,7 @@ impl<'info> Evaluator { let i = arguments_to_convert.len() - i_reverse - 1; let shrunk = self.shrink_bodyform_visited( allocator, - visited, + &mut visited, prog_args.clone(), env, arguments_to_convert[i].clone(), @@ -731,9 +832,25 @@ impl<'info> Evaluator { } } } + } else if let Some(applied_lambda) = self.is_lambda_apply( + allocator, + &mut visited, + prog_args.clone(), + env, + &target_vec, + only_inline + )? { + self.do_lambda_apply( + allocator, + &mut visited, + prog_args.clone(), + env, + &applied_lambda, + only_inline + ) } else { let reformed = BodyForm::Call(l.clone(), target_vec.clone()); - self.chase_apply(allocator, visited, Rc::new(reformed)) + self.chase_apply(allocator, &mut visited, Rc::new(reformed)) } }) .unwrap_or_else(|| { @@ -942,6 +1059,32 @@ impl<'info> Evaluator { } } + fn enrich_lambda_site_info( + &self, + allocator: &mut Allocator, + visited: &'info mut VisitedMarker<'_, VisitedInfo>, + prog_args: Rc, + env: &HashMap, Rc>, + ldata: &LambdaData, + only_inline: bool + ) -> Result, CompileErr> { + // Rewrite the captures based on what we know at the call site. + let new_captures = self.shrink_bodyform_visited( + allocator, + visited, + prog_args, + env, + ldata.captures.clone(), + only_inline + )?; + + // This is the first part of eta-conversion. + Ok(Rc::new(BodyForm::Lambda(LambdaData { + captures: new_captures, + .. ldata.clone() + }))) + } + // A frontend language evaluator and minifier pub fn shrink_bodyform_visited( &self, @@ -1108,6 +1251,16 @@ impl<'info> Evaluator { )?; Ok(Rc::new(BodyForm::Quoted(code))) } + BodyForm::Lambda(ldata) => { + self.enrich_lambda_site_info( + allocator, + &mut visited, + prog_args, + env, + ldata, + only_inline + ) + } } } diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index a846a88c3..ea93dde1c 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -75,6 +75,11 @@ fn collect_used_names_bodyform(body: &BodyForm) -> Vec> { result.append(&mut body_uses); result } + BodyForm::Lambda(ldata) => { + let mut capture_names = collect_used_names_bodyform(ldata.captures.borrow()); + capture_names.append(&mut collect_used_names_bodyform(ldata.body.borrow())); + capture_names + } } } @@ -283,7 +288,7 @@ pub fn compile_bodyform( match op.borrow() { SExp::Atom(l, atom_name) => { - if *atom_name == "q".as_bytes().to_vec() + if *atom_name == b"q" || (atom_name.len() == 1 && atom_name[0] == 1) { let tail_copy: &SExp = tail.borrow(); @@ -292,14 +297,14 @@ pub fn compile_bodyform( match tail.proper_list() { Some(v) => { - if *atom_name == "let".as_bytes().to_vec() - || *atom_name == "let*".as_bytes().to_vec() + if *atom_name == b"let" + || *atom_name == b"let*" { if v.len() != 2 { return finish_err("let"); } - let kind = if *atom_name == "let".as_bytes().to_vec() { + let kind = if *atom_name == b"let" { LetFormKind::Parallel } else { LetFormKind::Sequential @@ -320,7 +325,7 @@ pub fn compile_bodyform( body: Rc::new(compiled_body), }, )) - } else if *atom_name == "quote".as_bytes().to_vec() { + } else if *atom_name == b"quote" { if v.len() != 1 { return finish_err("quote"); } @@ -328,7 +333,7 @@ pub fn compile_bodyform( let quote_body = v[0].clone(); Ok(BodyForm::Quoted(quote_body)) - } else if *atom_name == "qq".as_bytes().to_vec() { + } else if *atom_name == b"qq" { if v.len() != 1 { return finish_err("qq"); } @@ -336,14 +341,14 @@ pub fn compile_bodyform( let quote_body = v[0].clone(); qq_to_expression(opts, Rc::new(quote_body)) - } else if *atom_name == "mod".as_bytes().to_vec() { + } else if *atom_name == b"mod" { let subparse = frontend(opts, &[body.clone()])?; Ok(BodyForm::Mod(op.loc(), false, subparse)) - } else if *atom_name == "mod+".as_bytes().to_vec() { + } else if *atom_name == b"mod+" { let subparse = frontend(opts, &[body.clone()])?; Ok(BodyForm::Mod(op.loc(), true, subparse)) - } else if *atom_name == "lambda".as_bytes().to_vec() { - handle_lambda(opts, &v) + } else if *atom_name == b"lambda" { + handle_lambda(opts, Some(l.clone()), v[0].loc(), &v) } else { application() } @@ -771,7 +776,6 @@ pub fn frontend( }; let our_mod = rename_children_compileform(&compiled?); - let expr_names: HashSet> = collect_used_names_bodyform(our_mod.exp.borrow()) .iter() .map(|x| x.to_vec()) diff --git a/src/compiler/inline.rs b/src/compiler/inline.rs index 0ec06efc1..116404aab 100644 --- a/src/compiler/inline.rs +++ b/src/compiler/inline.rs @@ -11,7 +11,7 @@ use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::compiler::codegen::{generate_expr_code, get_call_name, get_callable}; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ - BodyForm, Callable, CompileErr, CompiledCode, CompilerOpts, InlineFunction, PrimaryCodegen, + BodyForm, Callable, CompileErr, CompiledCode, CompilerOpts, InlineFunction, LambdaData, PrimaryCodegen, }; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; @@ -246,6 +246,23 @@ fn replace_inline_body( .unwrap_or_else(|| expr.clone()); Ok(alookup) } + BodyForm::Lambda(ldata) => { + let rewritten_captures = replace_inline_body( + visited_inlines, + runner, + opts, + compiler, + loc, + inline, + args, + callsite, + ldata.captures.clone() + )?; + Ok(Rc::new(BodyForm::Lambda(LambdaData { + captures: rewritten_captures, + .. ldata.clone() + }))) + } _ => Ok(expr.clone()), } } diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 5b21a95fa..7231f6c1d 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -4,9 +4,9 @@ use std::rc::Rc; use num_bigint::ToBigInt; use crate::compiler::clvm::truthy; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, PrimaryCodegen}; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, LambdaData, PrimaryCodegen}; use crate::compiler::evaluate::{make_operator1, make_operator2}; -use crate::compiler::frontend::{compile_bodyform, frontend}; +use crate::compiler::frontend::compile_bodyform; use crate::compiler::sexp::{enlist, SExp}; use crate::compiler::srcloc::Srcloc; @@ -35,7 +35,7 @@ fn make_captures(opts: Rc, sexp: Rc) -> Result, sexp: &SExp, -) -> Result<(Rc, Rc), CompileErr> { +) -> Result<(Rc, Rc, Rc), CompileErr> { let mut args = Rc::new(sexp.clone()); let mut capture_args = Rc::new(SExp::Nil(sexp.loc())); let mut captures = Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc()))); @@ -52,7 +52,8 @@ fn find_and_compose_captures( } Ok(( - Rc::new(SExp::Cons(sexp.loc(), capture_args, args)), + args, + capture_args, captures, )) } @@ -84,7 +85,7 @@ fn make_cons(loc: Srcloc, arg1: Rc, arg2: Rc) -> BodyForm { // // Lambda // -// (lambda ((= captures) arguments) +// (lambda ((& captures) arguments) // (body) // ) // @@ -96,63 +97,40 @@ fn make_cons(loc: Srcloc, arg1: Rc, arg2: Rc) -> BodyForm { // (list 4 (c 1 (@ 2)) (list 4 (c 1 compose_captures) @)) // ) // -pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result { - if v.len() < 2 { - return Err(CompileErr( - v[0].loc(), - "Must provide at least arguments and body to lambda".to_string(), - )); - } - - let (args, captures) = find_and_compose_captures(opts.clone(), &v[0])?; - eprintln!("args {args} captures {}", captures.to_sexp()); - - let rolled_elements_vec: Vec> = v.iter().skip(1).map(|x| Rc::new(x.clone())).collect(); - let body_list = enlist(v[0].loc(), rolled_elements_vec); - - // Make the mod form - let mod_form_data = Rc::new(SExp::Cons( - v[0].loc(), - Rc::new(SExp::atom_from_string(v[0].loc(), "mod+")), - Rc::new(SExp::Cons(args.loc(), args.clone(), Rc::new(body_list))), - )); - +pub fn lambda_codegen(opts: Rc, ldata: &LambdaData) -> Result { // Requires captures - let subparse = frontend(opts, &[mod_form_data])?; - let module = BodyForm::Mod(v[0].loc(), true, subparse); - // Code to retrieve the left env. let retrieve_left_env = Rc::new(make_operator1( - &v[0].loc(), + &ldata.loc, "@".to_string(), Rc::new(BodyForm::Value(SExp::Integer( - v[0].loc(), + ldata.loc.clone(), 2_u32.to_bigint().unwrap(), ))), )); // Code to retrieve and quote the captures. - let quote_atom = BodyForm::Value(SExp::Atom(v[0].loc(), vec![1])); - let apply_atom = BodyForm::Value(SExp::Atom(v[0].loc(), vec![2])); - let cons_atom = BodyForm::Value(SExp::Atom(v[0].loc(), vec![4])); + let quote_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![1])); + let apply_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![2])); + let cons_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![4])); let whole_env = quote_atom.clone(); - let compose_captures = make_cons(v[0].loc(), Rc::new(quote_atom.clone()), captures); - let quoted_code = make_cons(v[0].loc(), Rc::new(quote_atom.clone()), Rc::new(module)); + let compose_captures = make_cons(ldata.loc.clone(), Rc::new(quote_atom.clone()), ldata.captures.clone()); + let quoted_code = make_cons(ldata.loc.clone(), Rc::new(quote_atom.clone()), ldata.body.clone()); let lambda_output = make_call( - v[0].loc(), + ldata.loc.clone(), "list", &[ apply_atom, quoted_code, make_call( - v[0].loc(), + ldata.loc.clone(), "list", &[ cons_atom.clone(), - make_cons(v[0].loc(), Rc::new(quote_atom), retrieve_left_env), + make_cons(ldata.loc.clone(), Rc::new(quote_atom), retrieve_left_env), make_call( - v[0].loc(), + ldata.loc.clone(), "list", &[cons_atom, compose_captures, whole_env], ), @@ -162,3 +140,36 @@ pub fn handle_lambda(opts: Rc, v: &[SExp]) -> Result, kw_loc: Option, loc: Srcloc, v: &[SExp]) -> Result { + if v.len() < 2 { + return Err(CompileErr( + v[0].loc(), + "Must provide at least arguments and body to lambda".to_string(), + )); + } + + let (args, capture_args, captures) = find_and_compose_captures(opts.clone(), &v[0])?; + let combined_captures_and_args = Rc::new(SExp::Cons(args.loc(), capture_args.clone(), args.clone())); + + let rolled_elements_vec: Vec> = v.iter().skip(1).map(|x| Rc::new(x.clone())).collect(); + let body_list = enlist(v[0].loc(), rolled_elements_vec); + + // Make the mod form + let mod_form_data = Rc::new(SExp::Cons( + v[0].loc(), + Rc::new(SExp::atom_from_string(v[0].loc(), "mod+")), + Rc::new(SExp::Cons(args.loc(), combined_captures_and_args.clone(), Rc::new(body_list))), + )); + + // Requires captures + let subparse = compile_bodyform(opts, mod_form_data)?; + Ok(BodyForm::Lambda(LambdaData { + loc: v[0].loc(), + kw: kw_loc, + args: args.clone(), + capture_args: capture_args.clone(), + captures: captures, + body: Rc::new(subparse) + })) +} diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index d73822eb7..4d4378f9d 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -3,11 +3,10 @@ use std::collections::HashMap; use std::rc::Rc; use crate::compiler::comptypes::{ - Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LetData, - LetFormKind, + Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LambdaData, LetData, LetFormKind }; use crate::compiler::gensym::gensym; -use crate::compiler::sexp::SExp; +use crate::compiler::sexp::{decode_string, SExp}; fn rename_in_qq(namemap: &HashMap, Vec>, body: Rc) -> Rc { body.proper_list() @@ -116,6 +115,20 @@ fn make_binding_unique(b: &Binding) -> (Vec, Binding) { ) } +pub fn lambda_body_rename(namemap: &HashMap, Vec>, lambda_body: &BodyForm) -> BodyForm { + if let BodyForm::Mod(l, true, compiled) = lambda_body { + let new_args = rename_in_cons(namemap, compiled.args.clone()); + let new_body = rename_in_bodyform(namemap, compiled.exp.clone()); + BodyForm::Mod(l.clone(), true, CompileForm { + args: new_args, + exp: Rc::new(new_body), + .. compiled.clone() + }) + } else { + lambda_body.clone() + } +} + fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> BodyForm { match b.borrow() { BodyForm::Let(kind, letdata) => { @@ -168,6 +181,26 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B } BodyForm::Mod(l, left_env, prog) => BodyForm::Mod(l.clone(), *left_env, prog.clone()), + BodyForm::Lambda(ldata) => { + let namelist: Vec<(String, String)> = namemap.iter().map(|n| (decode_string(n.0),decode_string(n.1))).collect(); + let renamed_capture_inputs = Rc::new(rename_in_bodyform( + namemap, ldata.captures.clone() + )); + let renamed_capture_outputs = rename_in_cons( + namemap, ldata.capture_args.clone() + ); + let renamed_body = lambda_body_rename( + namemap, ldata.body.borrow() + ); + let result = + BodyForm::Lambda(LambdaData { + captures: renamed_capture_inputs, + capture_args: renamed_capture_outputs, + body: Rc::new(renamed_body), + .. ldata.clone() + }); + result + } } } @@ -255,6 +288,7 @@ fn rename_args_bodyform(b: &BodyForm) -> BodyForm { BodyForm::Call(l.clone(), new_vs) } BodyForm::Mod(l, left_env, program) => BodyForm::Mod(l.clone(), *left_env, program.clone()), + BodyForm::Lambda(ldata) => BodyForm::Lambda(ldata.clone()) } } @@ -331,6 +365,10 @@ fn rename_args_helperform(h: &HelperForm) -> HelperForm { } let local_renamed_arg = rename_in_cons(&local_namemap, defun.args.clone()); let local_renamed_body = rename_args_bodyform(defun.body.borrow()); + let renamed_bodyform = rename_in_bodyform( + &local_namemap, + Rc::new(local_renamed_body), + ); HelperForm::Defun( *inline, DefunData { @@ -339,10 +377,7 @@ fn rename_args_helperform(h: &HelperForm) -> HelperForm { kw: defun.kw.clone(), name: defun.name.clone(), args: local_renamed_arg, - body: Rc::new(rename_in_bodyform( - &local_namemap, - Rc::new(local_renamed_body), - )), + body: Rc::new(renamed_bodyform), }, ) } diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 340465bce..986845270 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -530,7 +530,7 @@ fn test_treehash_constant_embedded_modern_loop() { .trim() .to_string(); eprintln!("{result_text}"); - assert!(result_text.starts_with("*command*")); + // Asserting where the stack overflows isn't necessary. assert!(result_text.contains("stack limit exceeded")); } diff --git a/src/tests/compiler/evaluate.rs b/src/tests/compiler/evaluate.rs index 393342ddd..d220d62e5 100644 --- a/src/tests/compiler/evaluate.rs +++ b/src/tests/compiler/evaluate.rs @@ -118,3 +118,35 @@ fn test_simple_fe_opt_compile_1() { "(2 (1 1 . 99) (4 (1) 1))".to_string() ); } + +#[test] +fn test_lambda_eval_1() { + assert_eq!( + shrink_expr_from_string("(lambda (X) (+ X 1))".to_string()).unwrap(), + "(lambda (X) (+ X 1))".to_string() + ); +} + +#[test] +fn test_lambda_eval_2() { + assert_eq!( + shrink_expr_from_string("(a (lambda (X) (+ X 1)) (list 3))".to_string()).unwrap(), + "(q . 4)".to_string() + ); +} + +#[test] +fn test_lambda_eval_3() { + assert_eq!( + shrink_expr_from_string("(let ((L 10)) (a (lambda ((& L) X) (+ X L)) (list 3)))".to_string()).unwrap(), + "(q . 13)".to_string() + ); +} + +#[test] +fn test_lambda_eval_4() { + assert_eq!( + shrink_expr_from_string("(a (let ((L 10)) (lambda ((& L) X) (+ X L))) (list 3))".to_string()).unwrap(), + "(q . 13)".to_string() + ); +} diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index ab44e0533..638eb9d1d 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -228,13 +228,29 @@ fn test_eval_less_than_forever_recursive() { assert_eq!( test_repl_outcome_with_stack_limit( vec![ - "(defun tricky (N) (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ N 1)))))))))))))))))", - "(tricky 3)" - ], + "(defun tricky (N) (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ N 1)))))))))))))))))", + "(tricky 3)" + ], Some(50) ) - .unwrap() - .unwrap(), + .unwrap() + .unwrap(), "(q . 4)" ); } + +#[test] +fn test_lambda_eval_5() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun GetFun (L) (lambda ((& L) X) (+ X L)))", + "(a (GetFun 10) (list 3))" + ], + None + ) + .unwrap() + .unwrap(), + "(q . 13)" + ); +} From f771bb7e0cf8fcbacab4befd9218ade351349b38 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 27 Feb 2023 17:11:53 -0800 Subject: [PATCH 014/196] Move lambda desugaring later into codegen so the user will see their serialized code as having a lambda rather than a mod+ with desugared forms surrounding it. --- src/compiler/codegen.rs | 6 ++---- src/compiler/comptypes.rs | 3 +-- src/compiler/evaluate.rs | 6 +++--- src/compiler/frontend.rs | 2 +- src/compiler/lambda.rs | 44 +++++++++++++++++++++------------------ src/compiler/rename.rs | 17 +++++++-------- 6 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index eeebb8896..3b15a8765 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -585,7 +585,7 @@ pub fn generate_expr_code( allocator, runner, opts_with_env, - &program, + program, &mut HashMap::new(), )?; Ok(CompiledCode( @@ -611,9 +611,7 @@ pub fn generate_expr_code( )) } BodyForm::Lambda(ldata) => { - let desugared_lambda_callsite = lambda_codegen( - opts.clone(), &ldata - )?; + let desugared_lambda_callsite = lambda_codegen(ldata)?; let result = generate_expr_code( allocator, runner, diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index f0e06b455..ea7ee67c6 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -523,8 +523,7 @@ impl BodyForm { program.to_sexp(), )), BodyForm::Lambda(ldata) => { - let lambda = Rc::new(SExp::Atom(ldata.loc.clone(), b"lambda".to_vec())); - compose_lambda_serialized_form(&ldata) + compose_lambda_serialized_form(ldata) } } } diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 3bff67475..b579b4f0e 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -673,7 +673,7 @@ impl<'info> Evaluator { self.shrink_bodyform_visited( allocator, &mut visited, - prog_args.clone(), + prog_args, env, parts[2].clone(), only_inline @@ -683,7 +683,7 @@ impl<'info> Evaluator { return Ok(Some(LambdaApply { lambda: ldata.clone(), body: cf.exp.clone(), - env: evaluated_env.clone() + env: evaluated_env })); } } @@ -718,7 +718,7 @@ impl<'info> Evaluator { lapply.lambda.captures.clone(), only_inline )?; - let formed_caps = ArgInputs::Whole(reified_captures.clone()); + let formed_caps = ArgInputs::Whole(reified_captures); create_argument_captures( &mut lambda_env, &formed_caps, diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index ea93dde1c..5dc3f1490 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -348,7 +348,7 @@ pub fn compile_bodyform( let subparse = frontend(opts, &[body.clone()])?; Ok(BodyForm::Mod(op.loc(), true, subparse)) } else if *atom_name == b"lambda" { - handle_lambda(opts, Some(l.clone()), v[0].loc(), &v) + handle_lambda(opts, Some(l.clone()), &v) } else { application() } diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 7231f6c1d..2179c6cef 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -32,30 +32,34 @@ fn make_captures(opts: Rc, sexp: Rc) -> Result, + capture_args: Rc, + captures: Rc, +} + fn find_and_compose_captures( opts: Rc, sexp: &SExp, -) -> Result<(Rc, Rc, Rc), CompileErr> { - let mut args = Rc::new(sexp.clone()); - let mut capture_args = Rc::new(SExp::Nil(sexp.loc())); - let mut captures = Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc()))); +) -> Result { + let mut found = FoundLambdaCaptures { + args: Rc::new(sexp.clone()), + capture_args: Rc::new(SExp::Nil(sexp.loc())), + captures: Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc()))) + }; if let SExp::Cons(_, l, r) = sexp { if let SExp::Cons(_, head, rest) = l.borrow() { if let SExp::Atom(_, name) = head.borrow() { if name == b"&" { - args = r.clone(); - capture_args = rest.clone(); - captures = make_captures(opts, rest.clone())?; + found.args = r.clone(); + found.capture_args = rest.clone(); + found.captures = make_captures(opts, rest.clone())?; } } } } - Ok(( - args, - capture_args, - captures, - )) + Ok(found) } fn make_call(loc: Srcloc, head: &str, args: &[BodyForm]) -> BodyForm { @@ -97,7 +101,7 @@ fn make_cons(loc: Srcloc, arg1: Rc, arg2: Rc) -> BodyForm { // (list 4 (c 1 (@ 2)) (list 4 (c 1 compose_captures) @)) // ) // -pub fn lambda_codegen(opts: Rc, ldata: &LambdaData) -> Result { +pub fn lambda_codegen(ldata: &LambdaData) -> Result { // Requires captures // Code to retrieve the left env. let retrieve_left_env = Rc::new(make_operator1( @@ -141,7 +145,7 @@ pub fn lambda_codegen(opts: Rc, ldata: &LambdaData) -> Result< Ok(lambda_output) } -pub fn handle_lambda(opts: Rc, kw_loc: Option, loc: Srcloc, v: &[SExp]) -> Result { +pub fn handle_lambda(opts: Rc, kw_loc: Option, v: &[SExp]) -> Result { if v.len() < 2 { return Err(CompileErr( v[0].loc(), @@ -149,8 +153,8 @@ pub fn handle_lambda(opts: Rc, kw_loc: Option, loc: Sr )); } - let (args, capture_args, captures) = find_and_compose_captures(opts.clone(), &v[0])?; - let combined_captures_and_args = Rc::new(SExp::Cons(args.loc(), capture_args.clone(), args.clone())); + let found = find_and_compose_captures(opts.clone(), &v[0])?; + let combined_captures_and_args = Rc::new(SExp::Cons(found.args.loc(), found.capture_args.clone(), found.args.clone())); let rolled_elements_vec: Vec> = v.iter().skip(1).map(|x| Rc::new(x.clone())).collect(); let body_list = enlist(v[0].loc(), rolled_elements_vec); @@ -159,7 +163,7 @@ pub fn handle_lambda(opts: Rc, kw_loc: Option, loc: Sr let mod_form_data = Rc::new(SExp::Cons( v[0].loc(), Rc::new(SExp::atom_from_string(v[0].loc(), "mod+")), - Rc::new(SExp::Cons(args.loc(), combined_captures_and_args.clone(), Rc::new(body_list))), + Rc::new(SExp::Cons(found.args.loc(), combined_captures_and_args, Rc::new(body_list))), )); // Requires captures @@ -167,9 +171,9 @@ pub fn handle_lambda(opts: Rc, kw_loc: Option, loc: Sr Ok(BodyForm::Lambda(LambdaData { loc: v[0].loc(), kw: kw_loc, - args: args.clone(), - capture_args: capture_args.clone(), - captures: captures, + args: found.args.clone(), + capture_args: found.capture_args.clone(), + captures: found.captures, body: Rc::new(subparse) })) } diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 4d4378f9d..e871b3ae0 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -6,7 +6,7 @@ use crate::compiler::comptypes::{ Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LambdaData, LetData, LetFormKind }; use crate::compiler::gensym::gensym; -use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::sexp::SExp; fn rename_in_qq(namemap: &HashMap, Vec>, body: Rc) -> Rc { body.proper_list() @@ -182,7 +182,6 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B BodyForm::Mod(l, left_env, prog) => BodyForm::Mod(l.clone(), *left_env, prog.clone()), BodyForm::Lambda(ldata) => { - let namelist: Vec<(String, String)> = namemap.iter().map(|n| (decode_string(n.0),decode_string(n.1))).collect(); let renamed_capture_inputs = Rc::new(rename_in_bodyform( namemap, ldata.captures.clone() )); @@ -192,14 +191,12 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B let renamed_body = lambda_body_rename( namemap, ldata.body.borrow() ); - let result = - BodyForm::Lambda(LambdaData { - captures: renamed_capture_inputs, - capture_args: renamed_capture_outputs, - body: Rc::new(renamed_body), - .. ldata.clone() - }); - result + BodyForm::Lambda(LambdaData { + captures: renamed_capture_inputs, + capture_args: renamed_capture_outputs, + body: Rc::new(renamed_body), + .. ldata.clone() + }) } } } From 62f94a59586df21dba82daab7da884f854d811e9 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 27 Feb 2023 19:31:03 -0800 Subject: [PATCH 015/196] fmt --- src/compiler/codegen.rs | 2 +- src/compiler/comptypes.rs | 48 ++++++++------------ src/compiler/evaluate.rs | 83 ++++++++++++++++------------------ src/compiler/frontend.rs | 8 +--- src/compiler/inline.rs | 7 +-- src/compiler/lambda.rs | 34 +++++++++++--- src/compiler/rename.rs | 39 ++++++++-------- src/tests/compiler/evaluate.rs | 10 +++- src/tests/compiler/repl.rs | 4 +- 9 files changed, 120 insertions(+), 115 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 3b15a8765..61cf7b67b 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -617,7 +617,7 @@ pub fn generate_expr_code( runner, opts, compiler, - Rc::new(desugared_lambda_callsite) + Rc::new(desugared_lambda_callsite), )?; Ok(result) } diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index ea7ee67c6..e4c84f18a 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -429,39 +429,33 @@ impl HelperForm { fn compose_lambda_serialized_form(ldata: &LambdaData) -> Rc { let lambda_kw = Rc::new(SExp::Atom(ldata.loc.clone(), b"lambda".to_vec())); let amp_kw = Rc::new(SExp::Atom(ldata.loc.clone(), b"&".to_vec())); - let arguments = - if truthy(ldata.capture_args.clone()) { + let arguments = if truthy(ldata.capture_args.clone()) { + Rc::new(SExp::Cons( + ldata.loc.clone(), Rc::new(SExp::Cons( ldata.loc.clone(), - Rc::new(SExp::Cons( - ldata.loc.clone(), - amp_kw, - ldata.capture_args.clone() - )), - ldata.args.clone() - )) - } else { - ldata.args.clone() - }; - let rest_of_body = - if let SExp::Cons(_, _, after_kw) = ldata.body.to_sexp().borrow() { - if let SExp::Cons(_, _, after_args) = after_kw.borrow() { - after_args.clone() - } else { - Rc::new(SExp::Nil(ldata.loc.clone())) - } + amp_kw, + ldata.capture_args.clone(), + )), + ldata.args.clone(), + )) + } else { + ldata.args.clone() + }; + let rest_of_body = if let SExp::Cons(_, _, after_kw) = ldata.body.to_sexp().borrow() { + if let SExp::Cons(_, _, after_args) = after_kw.borrow() { + after_args.clone() } else { Rc::new(SExp::Nil(ldata.loc.clone())) - }; + } + } else { + Rc::new(SExp::Nil(ldata.loc.clone())) + }; Rc::new(SExp::Cons( ldata.loc.clone(), lambda_kw, - Rc::new(SExp::Cons( - ldata.loc.clone(), - arguments, - rest_of_body - )) + Rc::new(SExp::Cons(ldata.loc.clone(), arguments, rest_of_body)), )) } @@ -522,9 +516,7 @@ impl BodyForm { }, program.to_sexp(), )), - BodyForm::Lambda(ldata) => { - compose_lambda_serialized_form(ldata) - } + BodyForm::Lambda(ldata) => compose_lambda_serialized_form(ldata), } } } diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index b579b4f0e..7634ff947 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -13,7 +13,8 @@ use crate::compiler::clvm::run; use crate::compiler::codegen::codegen; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ - Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, LambdaData, LetData, LetFormKind, + Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, LambdaData, LetData, + LetFormKind, }; use crate::compiler::frontend::frontend; use crate::compiler::runtypes::RunFailure; @@ -65,7 +66,7 @@ impl<'info> VisitedInfoAccess for VisitedMarker<'info, VisitedInfo> { pub struct LambdaApply { lambda: LambdaData, body: Rc, - env: Rc + env: Rc, } // Frontend evaluator based on my fuzzer representation and direct interpreter of @@ -656,34 +657,32 @@ impl<'info> Evaluator { prog_args: Rc, env: &HashMap, Rc>, parts: &[Rc], - only_inline: bool + only_inline: bool, ) -> Result, CompileErr> { if parts.len() == 3 && is_apply_atom(parts[0].to_sexp()) { let mut visited = VisitedMarker::again(parts[0].loc(), visited_)?; - let evaluated_prog = - self.shrink_bodyform_visited( - allocator, - &mut visited, - prog_args.clone(), - env, - parts[1].clone(), - only_inline - )?; - let evaluated_env = - self.shrink_bodyform_visited( - allocator, - &mut visited, - prog_args, - env, - parts[2].clone(), - only_inline - )?; + let evaluated_prog = self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args.clone(), + env, + parts[1].clone(), + only_inline, + )?; + let evaluated_env = self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args, + env, + parts[2].clone(), + only_inline, + )?; if let BodyForm::Lambda(ldata) = evaluated_prog.borrow() { if let BodyForm::Mod(_, _, cf) = ldata.body.borrow() { return Ok(Some(LambdaApply { lambda: ldata.clone(), body: cf.exp.clone(), - env: evaluated_env + env: evaluated_env, })); } } @@ -716,22 +715,18 @@ impl<'info> Evaluator { prog_args.clone(), env, lapply.lambda.captures.clone(), - only_inline + only_inline, )?; let formed_caps = ArgInputs::Whole(reified_captures); create_argument_captures( &mut lambda_env, &formed_caps, - lapply.lambda.capture_args.clone() + lapply.lambda.capture_args.clone(), )?; // Create captures with the actual parameters. let formed_args = ArgInputs::Whole(lapply.env.clone()); - create_argument_captures( - &mut lambda_env, - &formed_args, - lapply.lambda.args.clone() - )?; + create_argument_captures(&mut lambda_env, &formed_args, lapply.lambda.args.clone())?; self.shrink_bodyform_visited( allocator, @@ -739,7 +734,7 @@ impl<'info> Evaluator { prog_args, &lambda_env, lapply.body.clone(), - only_inline + only_inline, ) } @@ -838,7 +833,7 @@ impl<'info> Evaluator { prog_args.clone(), env, &target_vec, - only_inline + only_inline, )? { self.do_lambda_apply( allocator, @@ -846,7 +841,7 @@ impl<'info> Evaluator { prog_args.clone(), env, &applied_lambda, - only_inline + only_inline, ) } else { let reformed = BodyForm::Call(l.clone(), target_vec.clone()); @@ -1066,7 +1061,7 @@ impl<'info> Evaluator { prog_args: Rc, env: &HashMap, Rc>, ldata: &LambdaData, - only_inline: bool + only_inline: bool, ) -> Result, CompileErr> { // Rewrite the captures based on what we know at the call site. let new_captures = self.shrink_bodyform_visited( @@ -1075,13 +1070,13 @@ impl<'info> Evaluator { prog_args, env, ldata.captures.clone(), - only_inline + only_inline, )?; // This is the first part of eta-conversion. Ok(Rc::new(BodyForm::Lambda(LambdaData { captures: new_captures, - .. ldata.clone() + ..ldata.clone() }))) } @@ -1251,16 +1246,14 @@ impl<'info> Evaluator { )?; Ok(Rc::new(BodyForm::Quoted(code))) } - BodyForm::Lambda(ldata) => { - self.enrich_lambda_site_info( - allocator, - &mut visited, - prog_args, - env, - ldata, - only_inline - ) - } + BodyForm::Lambda(ldata) => self.enrich_lambda_site_info( + allocator, + &mut visited, + prog_args, + env, + ldata, + only_inline, + ), } } diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 5dc3f1490..986fc7b68 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -288,18 +288,14 @@ pub fn compile_bodyform( match op.borrow() { SExp::Atom(l, atom_name) => { - if *atom_name == b"q" - || (atom_name.len() == 1 && atom_name[0] == 1) - { + if *atom_name == b"q" || (atom_name.len() == 1 && atom_name[0] == 1) { let tail_copy: &SExp = tail.borrow(); return Ok(BodyForm::Quoted(tail_copy.clone())); } match tail.proper_list() { Some(v) => { - if *atom_name == b"let" - || *atom_name == b"let*" - { + if *atom_name == b"let" || *atom_name == b"let*" { if v.len() != 2 { return finish_err("let"); } diff --git a/src/compiler/inline.rs b/src/compiler/inline.rs index 116404aab..4459eb0dd 100644 --- a/src/compiler/inline.rs +++ b/src/compiler/inline.rs @@ -11,7 +11,8 @@ use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::compiler::codegen::{generate_expr_code, get_call_name, get_callable}; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ - BodyForm, Callable, CompileErr, CompiledCode, CompilerOpts, InlineFunction, LambdaData, PrimaryCodegen, + BodyForm, Callable, CompileErr, CompiledCode, CompilerOpts, InlineFunction, LambdaData, + PrimaryCodegen, }; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; @@ -256,11 +257,11 @@ fn replace_inline_body( inline, args, callsite, - ldata.captures.clone() + ldata.captures.clone(), )?; Ok(Rc::new(BodyForm::Lambda(LambdaData { captures: rewritten_captures, - .. ldata.clone() + ..ldata.clone() }))) } _ => Ok(expr.clone()), diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 2179c6cef..bb0dca863 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -45,7 +45,7 @@ fn find_and_compose_captures( let mut found = FoundLambdaCaptures { args: Rc::new(sexp.clone()), capture_args: Rc::new(SExp::Nil(sexp.loc())), - captures: Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc()))) + captures: Rc::new(BodyForm::Quoted(SExp::Nil(sexp.loc()))), }; if let SExp::Cons(_, l, r) = sexp { if let SExp::Cons(_, head, rest) = l.borrow() { @@ -118,8 +118,16 @@ pub fn lambda_codegen(ldata: &LambdaData) -> Result { let cons_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![4])); let whole_env = quote_atom.clone(); - let compose_captures = make_cons(ldata.loc.clone(), Rc::new(quote_atom.clone()), ldata.captures.clone()); - let quoted_code = make_cons(ldata.loc.clone(), Rc::new(quote_atom.clone()), ldata.body.clone()); + let compose_captures = make_cons( + ldata.loc.clone(), + Rc::new(quote_atom.clone()), + ldata.captures.clone(), + ); + let quoted_code = make_cons( + ldata.loc.clone(), + Rc::new(quote_atom.clone()), + ldata.body.clone(), + ); let lambda_output = make_call( ldata.loc.clone(), @@ -145,7 +153,11 @@ pub fn lambda_codegen(ldata: &LambdaData) -> Result { Ok(lambda_output) } -pub fn handle_lambda(opts: Rc, kw_loc: Option, v: &[SExp]) -> Result { +pub fn handle_lambda( + opts: Rc, + kw_loc: Option, + v: &[SExp], +) -> Result { if v.len() < 2 { return Err(CompileErr( v[0].loc(), @@ -154,7 +166,11 @@ pub fn handle_lambda(opts: Rc, kw_loc: Option, v: &[SE } let found = find_and_compose_captures(opts.clone(), &v[0])?; - let combined_captures_and_args = Rc::new(SExp::Cons(found.args.loc(), found.capture_args.clone(), found.args.clone())); + let combined_captures_and_args = Rc::new(SExp::Cons( + found.args.loc(), + found.capture_args.clone(), + found.args.clone(), + )); let rolled_elements_vec: Vec> = v.iter().skip(1).map(|x| Rc::new(x.clone())).collect(); let body_list = enlist(v[0].loc(), rolled_elements_vec); @@ -163,7 +179,11 @@ pub fn handle_lambda(opts: Rc, kw_loc: Option, v: &[SE let mod_form_data = Rc::new(SExp::Cons( v[0].loc(), Rc::new(SExp::atom_from_string(v[0].loc(), "mod+")), - Rc::new(SExp::Cons(found.args.loc(), combined_captures_and_args, Rc::new(body_list))), + Rc::new(SExp::Cons( + found.args.loc(), + combined_captures_and_args, + Rc::new(body_list), + )), )); // Requires captures @@ -174,6 +194,6 @@ pub fn handle_lambda(opts: Rc, kw_loc: Option, v: &[SE args: found.args.clone(), capture_args: found.capture_args.clone(), captures: found.captures, - body: Rc::new(subparse) + body: Rc::new(subparse), })) } diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index e871b3ae0..deecb6ab9 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -3,7 +3,8 @@ use std::collections::HashMap; use std::rc::Rc; use crate::compiler::comptypes::{ - Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LambdaData, LetData, LetFormKind + Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LambdaData, + LetData, LetFormKind, }; use crate::compiler::gensym::gensym; use crate::compiler::sexp::SExp; @@ -119,11 +120,15 @@ pub fn lambda_body_rename(namemap: &HashMap, Vec>, lambda_body: &Bod if let BodyForm::Mod(l, true, compiled) = lambda_body { let new_args = rename_in_cons(namemap, compiled.args.clone()); let new_body = rename_in_bodyform(namemap, compiled.exp.clone()); - BodyForm::Mod(l.clone(), true, CompileForm { - args: new_args, - exp: Rc::new(new_body), - .. compiled.clone() - }) + BodyForm::Mod( + l.clone(), + true, + CompileForm { + args: new_args, + exp: Rc::new(new_body), + ..compiled.clone() + }, + ) } else { lambda_body.clone() } @@ -182,20 +187,15 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B BodyForm::Mod(l, left_env, prog) => BodyForm::Mod(l.clone(), *left_env, prog.clone()), BodyForm::Lambda(ldata) => { - let renamed_capture_inputs = Rc::new(rename_in_bodyform( - namemap, ldata.captures.clone() - )); - let renamed_capture_outputs = rename_in_cons( - namemap, ldata.capture_args.clone() - ); - let renamed_body = lambda_body_rename( - namemap, ldata.body.borrow() - ); + let renamed_capture_inputs = + Rc::new(rename_in_bodyform(namemap, ldata.captures.clone())); + let renamed_capture_outputs = rename_in_cons(namemap, ldata.capture_args.clone()); + let renamed_body = lambda_body_rename(namemap, ldata.body.borrow()); BodyForm::Lambda(LambdaData { captures: renamed_capture_inputs, capture_args: renamed_capture_outputs, body: Rc::new(renamed_body), - .. ldata.clone() + ..ldata.clone() }) } } @@ -285,7 +285,7 @@ fn rename_args_bodyform(b: &BodyForm) -> BodyForm { BodyForm::Call(l.clone(), new_vs) } BodyForm::Mod(l, left_env, program) => BodyForm::Mod(l.clone(), *left_env, program.clone()), - BodyForm::Lambda(ldata) => BodyForm::Lambda(ldata.clone()) + BodyForm::Lambda(ldata) => BodyForm::Lambda(ldata.clone()), } } @@ -362,10 +362,7 @@ fn rename_args_helperform(h: &HelperForm) -> HelperForm { } let local_renamed_arg = rename_in_cons(&local_namemap, defun.args.clone()); let local_renamed_body = rename_args_bodyform(defun.body.borrow()); - let renamed_bodyform = rename_in_bodyform( - &local_namemap, - Rc::new(local_renamed_body), - ); + let renamed_bodyform = rename_in_bodyform(&local_namemap, Rc::new(local_renamed_body)); HelperForm::Defun( *inline, DefunData { diff --git a/src/tests/compiler/evaluate.rs b/src/tests/compiler/evaluate.rs index d220d62e5..0c65619de 100644 --- a/src/tests/compiler/evaluate.rs +++ b/src/tests/compiler/evaluate.rs @@ -138,7 +138,10 @@ fn test_lambda_eval_2() { #[test] fn test_lambda_eval_3() { assert_eq!( - shrink_expr_from_string("(let ((L 10)) (a (lambda ((& L) X) (+ X L)) (list 3)))".to_string()).unwrap(), + shrink_expr_from_string( + "(let ((L 10)) (a (lambda ((& L) X) (+ X L)) (list 3)))".to_string() + ) + .unwrap(), "(q . 13)".to_string() ); } @@ -146,7 +149,10 @@ fn test_lambda_eval_3() { #[test] fn test_lambda_eval_4() { assert_eq!( - shrink_expr_from_string("(a (let ((L 10)) (lambda ((& L) X) (+ X L))) (list 3))".to_string()).unwrap(), + shrink_expr_from_string( + "(a (let ((L 10)) (lambda ((& L) X) (+ X L))) (list 3))".to_string() + ) + .unwrap(), "(q . 13)".to_string() ); } diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index 638eb9d1d..adf13178a 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -249,8 +249,8 @@ fn test_lambda_eval_5() { ], None ) - .unwrap() - .unwrap(), + .unwrap() + .unwrap(), "(q . 13)" ); } From 95d55bddef47c9aab92d88887819289e020ffa7f Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 2 Mar 2023 11:34:51 -0800 Subject: [PATCH 016/196] Add another test (trying more methods to think up tests) --- src/compiler/codegen.rs | 5 +++++ src/compiler/lambda.rs | 33 +++++++++++++++------------------ src/tests/compiler/compiler.rs | 23 +++++++++++++++++++++++ 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 61cf7b67b..43e853ce9 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -612,6 +612,11 @@ pub fn generate_expr_code( } BodyForm::Lambda(ldata) => { let desugared_lambda_callsite = lambda_codegen(ldata)?; + eprintln!("lambda callsite {}", desugared_lambda_callsite.to_sexp()); + eprintln!("helpers here:"); + for h in compiler.orig_help.iter() { + eprintln!("- {}", decode_string(h.name())); + } let result = generate_expr_code( allocator, runner, diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index bb0dca863..afb6ec7c6 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -62,15 +62,6 @@ fn find_and_compose_captures( Ok(found) } -fn make_call(loc: Srcloc, head: &str, args: &[BodyForm]) -> BodyForm { - let mut use_vec: Vec> = args.iter().cloned().map(Rc::new).collect(); - use_vec.insert( - 0, - Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), head))), - ); - BodyForm::Call(loc, use_vec) -} - fn make_operator(loc: Srcloc, op: u8, arg1: Rc, arg2: Rc) -> BodyForm { BodyForm::Call( loc.clone(), @@ -86,6 +77,18 @@ fn make_cons(loc: Srcloc, arg1: Rc, arg2: Rc) -> BodyForm { make_operator(loc, 4, arg1, arg2) } +fn make_list(loc: Srcloc, args: &[BodyForm]) -> BodyForm { + let mut res = BodyForm::Quoted(SExp::Nil(loc.clone())); + let cons_atom = BodyForm::Value(SExp::Atom(loc.clone(), vec![4])); + for a in args.iter().rev() { + res = BodyForm::Call( + loc.clone(), + vec![Rc::new(cons_atom.clone()), Rc::new(a.clone()), Rc::new(res)], + ); + } + res +} + // // Lambda // @@ -129,23 +132,17 @@ pub fn lambda_codegen(ldata: &LambdaData) -> Result { ldata.body.clone(), ); - let lambda_output = make_call( + let lambda_output = make_list( ldata.loc.clone(), - "list", &[ apply_atom, quoted_code, - make_call( + make_list( ldata.loc.clone(), - "list", &[ cons_atom.clone(), make_cons(ldata.loc.clone(), Rc::new(quote_atom), retrieve_left_env), - make_call( - ldata.loc.clone(), - "list", - &[cons_atom, compose_captures, whole_env], - ), + make_list(ldata.loc.clone(), &[cons_atom, compose_captures, whole_env]), ], ), ], diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 6cd6cfcee..de1bbae02 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1413,3 +1413,26 @@ fn test_lambda_reduce() { let res = run_string(&prog, &"(((2 3) (4 9)))".to_string()).unwrap(); assert_eq!(res.to_string(), "242"); } + +#[test] +fn test_lambda_as_let_binding() { + let prog = indoc! {" + (mod (P L) + (defun map (F L) + (if L (c (a F (list (f L))) (map F (r L))) ()) + ) + (defun x2 (N) (* 2 N)) + (defun x3p1 (N) (+ 1 (* 3 N))) + (let* ((H (lambda (N) (x2 N))) + (G (lambda (N) (x3p1 N))) + (F (if P G H))) + (map F L) + ) + ) + "} + .to_string(); + let res0 = run_string(&prog, &"(0 (1 2 3))".to_string()).unwrap(); + assert_eq!(res0.to_string(), "(2 4 6)"); + let res1 = run_string(&prog, &"(1 (1 2 3))".to_string()).unwrap(); + assert_eq!(res1.to_string(), "(4 7 10)"); +} From a5c986b0f340a2a6b0a5f6297eed8f70d3cd0958 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 2 Mar 2023 11:38:49 -0800 Subject: [PATCH 017/196] Add another similar test --- src/tests/compiler/compiler.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index de1bbae02..33c2461ee 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1436,3 +1436,25 @@ fn test_lambda_as_let_binding() { let res1 = run_string(&prog, &"(1 (1 2 3))".to_string()).unwrap(); assert_eq!(res1.to_string(), "(4 7 10)"); } + +#[test] +fn test_lambda_mixed_let_binding() { + let prog = indoc! {" + (mod (P L) + (defun map (F L) + (if L (c (a F (list (f L))) (map F (r L))) ()) + ) + (defun x2 (N) (* 2 N)) + (defun x3p1 (N) (+ 1 (* 3 N))) + (let* ((G (lambda (N) (x3p1 N))) + (F (if P G (lambda (N) (x2 N))))) + (map F L) + ) + ) + "} + .to_string(); + let res0 = run_string(&prog, &"(0 (1 2 3))".to_string()).unwrap(); + assert_eq!(res0.to_string(), "(2 4 6)"); + let res1 = run_string(&prog, &"(1 (1 2 3))".to_string()).unwrap(); + assert_eq!(res1.to_string(), "(4 7 10)"); +} From 4c5bf29d770d751c4ed9cfc2f413fb50cc198ef5 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 2 Mar 2023 11:44:02 -0800 Subject: [PATCH 018/196] Remove spam --- src/compiler/codegen.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 43e853ce9..61cf7b67b 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -612,11 +612,6 @@ pub fn generate_expr_code( } BodyForm::Lambda(ldata) => { let desugared_lambda_callsite = lambda_codegen(ldata)?; - eprintln!("lambda callsite {}", desugared_lambda_callsite.to_sexp()); - eprintln!("helpers here:"); - for h in compiler.orig_help.iter() { - eprintln!("- {}", decode_string(h.name())); - } let result = generate_expr_code( allocator, runner, From beb5e677d1aa0b8cadba22f31189f6e55ad0e78f Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 2 Mar 2023 11:54:27 -0800 Subject: [PATCH 019/196] Add a tricky test where a lambda is used as a higher order function --- src/tests/compiler/compiler.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 33c2461ee..d6ded356a 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1458,3 +1458,15 @@ fn test_lambda_mixed_let_binding() { let res1 = run_string(&prog, &"(1 (1 2 3))".to_string()).unwrap(); assert_eq!(res1.to_string(), "(4 7 10)"); } + +#[test] +fn test_lambda_hof_1() { + let prog = indoc! {" + (mod (P) + (a (a (lambda ((& P) X) (lambda ((& P X)) (+ P X))) (list 3)) ()) + ) + "} + .to_string(); + let res = run_string(&prog, &"(1)".to_string()).unwrap(); + assert_eq!(res.to_string(), "4"); +} From f850d91faa83c69b1fcd6dfb8754217f9ec69c4d Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 2 Mar 2023 14:40:29 -0800 Subject: [PATCH 020/196] Add another test i could think of --- src/tests/compiler/compiler.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index d6ded356a..3630a78ff 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1470,3 +1470,21 @@ fn test_lambda_hof_1() { let res = run_string(&prog, &"(1)".to_string()).unwrap(); assert_eq!(res.to_string(), "4"); } + +#[test] +fn test_lambda_as_argument_to_prim() { + let prog = indoc! {" + (mod (P) + (defun map-f (A L) + (if L (c (a (f L) A) (map-f A (r L))) ()) + ) + (let ((Fs (list (lambda (X) (- X 1)) (lambda (X) (+ X 1)) (lambda (X) (* 2 X)))) + (args (list P))) + (map-f args Fs) + ) + ) + "} + .to_string(); + let res = run_string(&prog, &"(10)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(9 11 20)"); +} From c9966730c6acd8b114fd434412206f32b75eff32 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 2 Mar 2023 14:43:20 -0800 Subject: [PATCH 021/196] More tricky lambda tests --- src/tests/compiler/compiler.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 3630a78ff..de5ad463f 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1472,7 +1472,7 @@ fn test_lambda_hof_1() { } #[test] -fn test_lambda_as_argument_to_prim() { +fn test_lambda_as_argument_to_macro() { let prog = indoc! {" (mod (P) (defun map-f (A L) @@ -1488,3 +1488,21 @@ fn test_lambda_as_argument_to_prim() { let res = run_string(&prog, &"(10)".to_string()).unwrap(); assert_eq!(res.to_string(), "(9 11 20)"); } + +#[test] +fn test_lambda_as_argument_to_macro_with_inner_let() { + let prog = indoc! {" + (mod (P) + (defun map-f (A L) + (if L (c (a (f L) A) (map-f A (r L))) ()) + ) + (let ((Fs (list (lambda (X) (let ((N (* X 3))) N)) (lambda (X) (+ X 1)) (lambda (X) (* 2 X)))) + (args (list P))) + (map-f args Fs) + ) + ) + "} + .to_string(); + let res = run_string(&prog, &"(10)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(30 11 20)"); +} From 8f0dfe2bf379cd077bc098fdd64f6ff76fbde2ad Mon Sep 17 00:00:00 2001 From: arty Date: Sat, 4 Mar 2023 04:58:59 -0800 Subject: [PATCH 022/196] WIP getting a little farther --- src/compiler/preprocessor.rs | 268 +++++++++++++++++---------------- src/tests/compiler/compiler.rs | 13 ++ 2 files changed, 153 insertions(+), 128 deletions(-) diff --git a/src/compiler/preprocessor.rs b/src/compiler/preprocessor.rs index 9d364cfe4..ef1604e09 100644 --- a/src/compiler/preprocessor.rs +++ b/src/compiler/preprocessor.rs @@ -1,50 +1,61 @@ use std::borrow::Borrow; use std::rc::Rc; +use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; + use crate::compiler::compiler::KNOWN_DIALECTS; use crate::compiler::comptypes::{CompileErr, CompilerOpts, IncludeDesc}; +use crate::compiler::evaluate::Evaluator; use crate::compiler::sexp::{decode_string, enlist, parse_sexp, SExp}; use crate::compiler::srcloc::Srcloc; use crate::util::ErrInto; -pub fn process_include( +struct Preprocessor { opts: Rc, - include: IncludeDesc, -) -> Result>, CompileErr> { - let filename_and_content = opts.read_new_file(opts.filename(), decode_string(&include.name))?; - let content = filename_and_content.1; - let start_of_file = Srcloc::start(&decode_string(&include.name)); - - // Because we're also subsequently returning CompileErr later in the pipe, - // this needs an explicit err map. - parse_sexp(start_of_file.clone(), content.bytes()) - .err_into() - .and_then(|x| match x[0].proper_list() { - None => Err(CompileErr( - start_of_file, - "Includes should contain a list of forms".to_string(), - )), - Some(v) => Ok(v.iter().map(|x| Rc::new(x.clone())).collect()), - }) + evaluator: Evaluator } -/* Expand include inline in forms */ -fn process_pp_form( - opts: Rc, - includes: &mut Vec, - body: Rc, -) -> Result>, CompileErr> { - // Support using the preprocessor to collect dependencies recursively. - let recurse_dependencies = |opts: Rc, - includes: &mut Vec, - desc: IncludeDesc| - -> Result<(), CompileErr> { +impl Preprocessor { + pub fn new(opts: Rc) -> Self { + let runner = Rc::new(DefaultProgramRunner::new()); + Preprocessor { + opts: opts.clone(), + evaluator: Evaluator::new(opts, runner, Vec::new()) + } + } + + pub fn process_include( + &mut self, + include: IncludeDesc, + ) -> Result>, CompileErr> { + let filename_and_content = self.opts.read_new_file(self.opts.filename(), decode_string(&include.name))?; + let content = filename_and_content.1; + let start_of_file = Srcloc::start(&decode_string(&include.name)); + + // Because we're also subsequently returning CompileErr later in the pipe, + // this needs an explicit err map. + parse_sexp(start_of_file.clone(), content.bytes()) + .err_into() + .and_then(|x| match x[0].proper_list() { + None => Err(CompileErr( + start_of_file, + "Includes should contain a list of forms".to_string(), + )), + Some(v) => Ok(v.iter().map(|x| Rc::new(x.clone())).collect()), + }) + } + + fn recurse_dependencies( + &mut self, + includes: &mut Vec, + desc: IncludeDesc + ) -> Result<(), CompileErr> { let name_string = decode_string(&desc.name); if KNOWN_DIALECTS.contains_key(&name_string) { return Ok(()); } - let (full_name, content) = opts.read_new_file(opts.filename(), name_string)?; + let (full_name, content) = self.opts.read_new_file(self.opts.filename(), name_string)?; includes.push(IncludeDesc { name: full_name.as_bytes().to_vec(), ..desc @@ -58,123 +69,127 @@ fn process_pp_form( let program_form = parsed[0].clone(); if let Some(l) = program_form.proper_list() { for elt in l.iter() { - process_pp_form(opts.clone(), includes, Rc::new(elt.clone()))?; + self.process_pp_form(includes, Rc::new(elt.clone()))?; } } Ok(()) - }; - - let included: Option = body - .proper_list() - .map(|x| x.iter().map(|elt| elt.atomize()).collect()) - .map(|x: Vec| { - match &x[..] { - [SExp::Atom(kw, inc), SExp::Atom(nl, fname)] => { - if "include".as_bytes().to_vec() == *inc { - return Ok(Some(IncludeDesc { - kw: kw.clone(), - nl: nl.clone(), - name: fname.clone(), - })); + } + + /* Expand include inline in forms */ + fn process_pp_form( + &mut self, + includes: &mut Vec, + body: Rc, + ) -> Result>, CompileErr> { + // Support using the preprocessor to collect dependencies recursively. + let included: Option = body + .proper_list() + .map(|x| x.iter().map(|elt| elt.atomize()).collect()) + .map(|x: Vec| { + match &x[..] { + [SExp::Atom(kw, inc), SExp::Atom(nl, fname)] => { + if "include".as_bytes().to_vec() == *inc { + return Ok(Some(IncludeDesc { + kw: kw.clone(), + nl: nl.clone(), + name: fname.clone(), + })); + } } - } - [SExp::Atom(kw, inc), SExp::QuotedString(nl, _, fname)] => { - if "include".as_bytes().to_vec() == *inc { - return Ok(Some(IncludeDesc { - kw: kw.clone(), - nl: nl.clone(), - name: fname.clone(), - })); + [SExp::Atom(kw, inc), SExp::QuotedString(nl, _, fname)] => { + if "include".as_bytes().to_vec() == *inc { + return Ok(Some(IncludeDesc { + kw: kw.clone(), + nl: nl.clone(), + name: fname.clone(), + })); + } } - } - [] => {} - - // Ensure that legal empty or atom expressions don't try include - _ => { - // Include is only allowed as a proper form. It's a keyword in - // this language. - if let SExp::Atom(_, inc) = &x[0] { - if "include".as_bytes().to_vec() == *inc { - return Err(CompileErr( - body.loc(), - format!("bad tail in include {body}"), - )); + [] => {} + + // Ensure that legal empty or atom expressions don't try include + _ => { + // Include is only allowed as a proper form. It's a keyword in + // this language. + if let SExp::Atom(_, inc) = &x[0] { + if "include".as_bytes().to_vec() == *inc { + return Err(CompileErr( + body.loc(), + format!("bad tail in include {body}"), + )); + } } } } - } - Ok(None) - }) - .unwrap_or_else(|| Ok(None))?; + Ok(None) + }) + .unwrap_or_else(|| Ok(None))?; - if let Some(i) = included { - recurse_dependencies(opts.clone(), includes, i.clone())?; - process_include(opts, i) - } else { - Ok(vec![body]) + if let Some(i) = included { + self.recurse_dependencies(includes, i.clone())?; + self.process_include(i) + } else { + Ok(vec![body]) + } } -} -fn preprocess_( - opts: Rc, - includes: &mut Vec, - body: Rc, -) -> Result>, CompileErr> { - match body.borrow() { - SExp::Cons(_, head, rest) => match rest.borrow() { - SExp::Nil(_nl) => process_pp_form(opts, includes, head.clone()), + fn inject_std_macros(&mut self, body: Rc) -> SExp { + match body.proper_list() { + Some(v) => { + let include_form = Rc::new(SExp::Cons( + body.loc(), + Rc::new(SExp::atom_from_string(body.loc(), "include")), + Rc::new(SExp::Cons( + body.loc(), + Rc::new(SExp::quoted_from_string(body.loc(), "*macros*")), + Rc::new(SExp::Nil(body.loc())), + )), + )); + let mut v_clone: Vec> = v.iter().map(|x| Rc::new(x.clone())).collect(); + let include_copy: &SExp = include_form.borrow(); + v_clone.insert(0, Rc::new(include_copy.clone())); + enlist(body.loc(), v_clone) + } _ => { - let lst = process_pp_form(opts.clone(), includes, head.clone())?; - let mut rs = preprocess_(opts, includes, rest.clone())?; - let mut result = lst; - result.append(&mut rs); - Ok(result) + let body_clone: &SExp = body.borrow(); + body_clone.clone() } - }, - _ => Ok(vec![body]), + } } -} -fn inject_std_macros(body: Rc) -> SExp { - match body.proper_list() { - Some(v) => { - let include_form = Rc::new(SExp::Cons( - body.loc(), - Rc::new(SExp::atom_from_string(body.loc(), "include")), - Rc::new(SExp::Cons( - body.loc(), - Rc::new(SExp::quoted_from_string(body.loc(), "*macros*")), - Rc::new(SExp::Nil(body.loc())), - )), - )); - let mut v_clone: Vec> = v.iter().map(|x| Rc::new(x.clone())).collect(); - let include_copy: &SExp = include_form.borrow(); - v_clone.insert(0, Rc::new(include_copy.clone())); - enlist(body.loc(), v_clone) - } - _ => { - let body_clone: &SExp = body.borrow(); - body_clone.clone() + pub fn run( + &mut self, + includes: &mut Vec, + cmod: Rc, + ) -> Result>, CompileErr> { + let mut result = Vec::new(); + let mut tocompile = if self.opts.stdenv() { + let injected = self.inject_std_macros(cmod); + Rc::new(injected) + } else { + cmod + }; + + while let SExp::Cons(_,f,r) = tocompile.borrow() { + let mut lst = self.process_pp_form(includes, f.clone())?; + result.append(&mut lst); + tocompile = r.clone(); } + + Ok(result) } } pub fn preprocess( opts: Rc, includes: &mut Vec, - cmod: Rc, + cmod: Rc ) -> Result>, CompileErr> { - let tocompile = if opts.stdenv() { - let injected = inject_std_macros(cmod); - Rc::new(injected) - } else { - cmod - }; - - preprocess_(opts, includes, tocompile) + let mut p = Preprocessor::new(opts); + p.run(includes, cmod) } // Visit all files used during compilation. @@ -184,6 +199,7 @@ pub fn gather_dependencies( file_content: &str, ) -> Result, CompileErr> { let mut includes = Vec::new(); + let mut p = Preprocessor::new(opts); let loc = Srcloc::start(real_input_path); let parsed = parse_sexp(loc.clone(), file_content.bytes())?; @@ -192,13 +208,9 @@ pub fn gather_dependencies( return Ok(vec![]); } - if let Some(l) = parsed[0].proper_list() { - for elt in l.iter() { - process_pp_form(opts.clone(), &mut includes, Rc::new(elt.clone()))?; - } - } else { - return Err(CompileErr(loc, "malformed list body".to_string())); - }; + for elt in parsed.iter() { + p.run(&mut includes, elt.clone())?; + } Ok(includes) } diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index a06879f96..85741c97f 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1192,3 +1192,16 @@ fn test_inline_out_of_bounds_diagnostic() { assert!(false); } } + +#[test] +fn test_defmac_basic_0() { + let prog = indoc! {" + (defmac double-arg (A) (list (concat A \"1\") (concat A \"2\"))) + (mod (double-arg X) + (+ X1 X2) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3 4)".to_string()).unwrap(); + assert_eq!(res.to_string(), "7"); +} From e25bf6310157f2e6fe6fd8ce931c2e0a124281df Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 8 Mar 2023 23:31:28 -0800 Subject: [PATCH 023/196] Updates, WIP --- src/compiler/evaluate.rs | 36 ++++++- src/compiler/frontend.rs | 2 +- src/compiler/preprocessor.rs | 169 +++++++++++++++++++++++++++++++-- src/compiler/sexp.rs | 116 ++++++++++++++++++++++ src/tests/compiler/compiler.rs | 7 +- 5 files changed, 316 insertions(+), 14 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 541c8c8b3..8f4a1cc18 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -70,10 +70,23 @@ pub enum ArgInputs { Pair(Rc, Rc), } +pub trait EvalExtension { + fn try_eval( + &self, + evaluator: &Evaluator, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result>, CompileErr>; +} + pub struct Evaluator { opts: Rc, runner: Rc, prims: Rc, Rc>>, + extensions: Vec>, helpers: Vec, mash_conditions: bool, ignore_exn: bool, @@ -151,7 +164,7 @@ fn get_bodyform_from_arginput(l: &Srcloc, arginput: &ArgInputs) -> Rc // // It's possible this will result in irreducible (unknown at compile time) // argument expressions. -fn create_argument_captures( +pub fn create_argument_captures( argument_captures: &mut HashMap, Rc>, formed_arguments: &ArgInputs, function_arg_spec: Rc, @@ -248,7 +261,7 @@ fn arg_inputs_primitive(arginputs: Rc) -> bool { } } -fn build_argument_captures( +pub fn build_argument_captures( l: &Srcloc, arguments_to_convert: &[Rc], args: Rc, @@ -574,6 +587,7 @@ impl<'info> Evaluator { helpers, mash_conditions: false, ignore_exn: false, + extensions: Vec::new() } } @@ -583,6 +597,7 @@ impl<'info> Evaluator { runner: self.runner.clone(), prims: self.prims.clone(), helpers: self.helpers.clone(), + extensions: self.extensions.clone(), mash_conditions: true, ignore_exn: true, } @@ -688,6 +703,19 @@ impl<'info> Evaluator { let compiled_borrowed: &SExp = compiled.borrow(); Ok(Rc::new(BodyForm::Quoted(compiled_borrowed.clone()))) } else { + for ext in self.extensions.iter() { + if let Some(res) = ext.try_eval( + self, + env, + &l, + call_name, + arguments_to_convert, + body.clone() + )? { + return Ok(res); + } + } + let pres = self .lookup_prim(l.clone(), call_name) .map(|prim| { @@ -1253,6 +1281,10 @@ impl<'info> Evaluator { self.helpers.push(h.clone()); } + pub fn add_extension(&mut self, e: Rc) { + self.extensions.push(e); + } + // The evaluator treats the forms coming up from constants as live. fn get_constant(&self, name: &[u8]) -> Option> { for h in self.helpers.iter() { diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index b25b967c0..2dbdf2a12 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -565,7 +565,7 @@ pub fn compile_helperform( matched.args, ) .map(Some) - } else if matched.op_name == b"defmacro" { + } else if matched.op_name == b"defmacro" || matched.op_name == b"defmac" { compile_defmacro( opts, l, diff --git a/src/compiler/preprocessor.rs b/src/compiler/preprocessor.rs index ef1604e09..32b96e98e 100644 --- a/src/compiler/preprocessor.rs +++ b/src/compiler/preprocessor.rs @@ -1,26 +1,69 @@ use std::borrow::Borrow; +use std::collections::HashMap; use std::rc::Rc; +use clvmr::allocator::Allocator; + use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::compiler::compiler::KNOWN_DIALECTS; -use crate::compiler::comptypes::{CompileErr, CompilerOpts, IncludeDesc}; -use crate::compiler::evaluate::Evaluator; -use crate::compiler::sexp::{decode_string, enlist, parse_sexp, SExp}; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc}; +use crate::compiler::evaluate::{ArgInputs, create_argument_captures, dequote, EvalExtension, Evaluator}; +use crate::compiler::frontend::compile_helperform; +use crate::compiler::sexp::{Atom, decode_string, enlist, First, NodeSel, parse_sexp, SelectNode, SExp, ThisNode}; use crate::compiler::srcloc::Srcloc; use crate::util::ErrInto; struct Preprocessor { opts: Rc, - evaluator: Evaluator + evaluator: Evaluator, + helpers: Vec, +} + +struct PreprocessorExtension { } +impl EvalExtension for PreprocessorExtension { + fn try_eval( + &self, + evaluator: &Evaluator, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result>, CompileErr> { + if name == b"string->symbol" { + if args.len() != 1 { + return Err(CompileErr(loc.clone(), "string->symbol needs 1 argument".to_string())); + } + + eprintln!("args[0] {}", args[0].to_sexp()); + + if let BodyForm::Quoted(SExp::QuotedString(al,_,an)) = args[0].borrow() { + return Ok(Some(Rc::new(BodyForm::Quoted(SExp::Atom(al.clone(),an.clone()))))); + } else if let BodyForm::Quoted(x) = args[0].borrow() { + return Err(CompileErr(loc.clone(), "string->symbol takes a string".to_string())); + } else { + return Ok(Some(body.clone())); + } + } + + Ok(None) + } +} + +impl PreprocessorExtension { + fn new() -> Self { PreprocessorExtension { } } } impl Preprocessor { pub fn new(opts: Rc) -> Self { let runner = Rc::new(DefaultProgramRunner::new()); + let mut eval = Evaluator::new(opts.clone(), runner, Vec::new()); + eval.add_extension(Rc::new(PreprocessorExtension::new())); Preprocessor { opts: opts.clone(), - evaluator: Evaluator::new(opts, runner, Vec::new()) + evaluator: eval, + helpers: Vec::new() } } @@ -76,12 +119,114 @@ impl Preprocessor { Ok(()) } + // Check for and apply preprocessor level macros. + // This is maximally permissive. + fn expand_macros( + &mut self, + body: Rc + ) -> Result, CompileErr> { + eprintln!("expand_macros {}", body); + if let SExp::Cons(l,f,r) = body.borrow() { + // First expand inner macros. + let first_expanded = self.expand_macros(f.clone())?; + let rest_expanded = self.expand_macros(r.clone())?; + let new_self = SExp::Cons(l.clone(), first_expanded, rest_expanded); + if let Ok(NodeSel::Cons((nl, name), args)) = NodeSel::Cons( + Atom::Here(()), ThisNode::Here + ).select_nodes(body.clone()) { + // See if it's a form that calls one of our macros. + for m in self.helpers.iter() { + eprintln!("want {} helper {}", decode_string(&name), m.to_sexp()); + if let HelperForm::Defun(_,mdata) = &m { // We record upfront macros + if mdata.name != name { + continue; + } + + // as inline defuns because they're closest to that + // semantically. + let mut allocator = Allocator::new(); + // The name matched, try calling it. + + // Form argument env. + let mut macro_arg_env = HashMap::new(); + let args_borrowed: &SExp = args.borrow(); + create_argument_captures( + &mut macro_arg_env, + &ArgInputs::Whole(Rc::new(BodyForm::Quoted(args_borrowed.clone()))), + mdata.args.clone() + )?; + + let res = self.evaluator.shrink_bodyform( + &mut allocator, + mdata.args.clone(), + ¯o_arg_env, + mdata.body.clone(), + false, + None + )?; + + eprintln!("shrink res {}", res.to_sexp()); + + if let Ok(unquoted) = dequote(body.loc(), res) { + return Ok(unquoted); + } + } + } + } + } + + Ok(body) + } + + // If it's a defmac (preprocessor level macro), add it to the evaulator. + fn decode_macro( + &mut self, + definition: Rc + ) -> Result, CompileErr> { + eprintln!("decode_macro {definition}"); + if let Ok(NodeSel::Cons( + defmac_loc, + NodeSel::Cons( + (nl, name), + NodeSel::Cons(args,body) + ) + )) = NodeSel::Cons( + Atom::Here("defmac"), + NodeSel::Cons( + Atom::Here(()), + NodeSel::Cons(ThisNode::Here, ThisNode::Here) + ) + ).select_nodes(definition.clone()) { + let target_defun = Rc::new(SExp::Cons( + defmac_loc.clone(), + Rc::new(SExp::atom_from_string(defmac_loc.clone(), "defun")), + Rc::new(SExp::Cons( + nl.clone(), + Rc::new(SExp::Atom(nl.clone(), name.clone())), + Rc::new(SExp::Cons( + args.loc(), args.clone(), body.clone() + )) + )) + )); + eprintln!("target_defun {target_defun}"); + if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { + self.evaluator.add_helper(&helper); + self.helpers.push(helper); + } else { + return Err(CompileErr(definition.loc(), "defmac found but couldn't be converted to function".to_string())); + } + } + + Ok(None) + } + /* Expand include inline in forms */ fn process_pp_form( &mut self, includes: &mut Vec, - body: Rc, + unexpanded_body: Rc, ) -> Result>, CompileErr> { + let body = self.expand_macros(unexpanded_body)?; // Support using the preprocessor to collect dependencies recursively. let included: Option = body .proper_list() @@ -119,6 +264,11 @@ impl Preprocessor { body.loc(), format!("bad tail in include {body}"), )); + } else { + // Try to pick up helperforms. + if let Some(()) = self.decode_macro(body.clone())? { + return Ok(None); + } } } } @@ -128,7 +278,9 @@ impl Preprocessor { }) .unwrap_or_else(|| Ok(None))?; - if let Some(i) = included { + if let Some(()) = self.decode_macro(body.clone())? { + Ok(vec![]) + } else if let Some(i) = included { self.recurse_dependencies(includes, i.clone())?; self.process_include(i) } else { @@ -199,7 +351,8 @@ pub fn gather_dependencies( file_content: &str, ) -> Result, CompileErr> { let mut includes = Vec::new(); - let mut p = Preprocessor::new(opts); + let no_stdenv_opts = opts.set_stdenv(false); + let mut p = Preprocessor::new(no_stdenv_opts); let loc = Srcloc::start(real_input_path); let parsed = parse_sexp(loc.clone(), file_content.bytes())?; diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index d50ff13d2..f593754a3 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -804,3 +804,119 @@ where { parse_sexp_inner(start, SExpParseState::Empty, input) } + +// This is a trait that generates a haskell-like ad-hoc type from the user's +// construction of NodeSel and ThisNode. +// the result is transformed into a NodeSel tree of NodePtr if it can be. +// The type of the result is an ad-hoc shape derived from the shape of the +// original request. +// +// This mirrors code in src/classic/clvm/sexp.rs +// +// It's a nicer way of modelling matches that will overtake bespoke code for a lot +// of things. +#[derive(Debug, Clone)] +pub enum NodeSel { + Cons(T, U), +} + +#[derive(Debug, Clone)] +pub enum First { + Here(T), +} + +#[derive(Debug, Clone)] +pub enum Rest { + Here(T), +} + +#[derive(Debug, Clone)] +pub enum ThisNode { + Here, +} + +pub enum Atom { + Here(T), +} + +pub trait SelectNode { + fn select_nodes(&self, s: Rc) -> Result; +} + +impl SelectNode, E> for ThisNode { + fn select_nodes(&self, s: Rc) -> Result, E> { + Ok(s) + } +} + +impl SelectNode<(Srcloc, Vec), (Srcloc, String)> for Atom<()> { + fn select_nodes(&self, s: Rc) -> Result<(Srcloc, Vec), (Srcloc, String)> + { + if let SExp::Atom(loc,name) = s.borrow() { + return Ok((loc.clone(),name.clone())); + } + + Err((s.loc(), "Not an atom".to_string())) + } +} + +impl SelectNode for Atom<&str> { + fn select_nodes(&self, s: Rc) -> Result { + let Atom::Here(name) = self; + if let Ok((l,n)) = Atom::Here(()).select_nodes(s.clone()) { + if n == name.as_bytes() { + return Ok(l.clone()); + } + } + + Err((s.loc(), format!("Not an atom named {name}"))) + } +} + +impl SelectNode<(), E> for () { + fn select_nodes(&self, _n: Rc) -> Result<(), E> { + Ok(()) + } +} + +impl SelectNode, E> for First +where + R: SelectNode + Clone, + E: From<(Srcloc, String)>, +{ + fn select_nodes(&self, s: Rc) -> Result, E> { + let First::Here(f) = &self; + let NodeSel::Cons(first, ()) = NodeSel::Cons(f.clone(), ()).select_nodes(s)?; + Ok(First::Here(first)) + } +} + +impl SelectNode, E> for Rest +where + R: SelectNode + Clone, + E: From<(Srcloc, String)>, +{ + fn select_nodes(&self, s: Rc) -> Result, E> { + let Rest::Here(f) = &self; + let NodeSel::Cons((), rest) = NodeSel::Cons((), f.clone()).select_nodes(s)?; + Ok(Rest::Here(rest)) + } +} + +impl SelectNode, E> for NodeSel +where + R: SelectNode, + S: SelectNode, + E: From<(Srcloc, String)>, +{ + fn select_nodes(&self, s: Rc) -> Result, E> { + let NodeSel::Cons(my_left, my_right) = &self; + if let SExp::Cons(_, l, r) = s.borrow() { + let first = my_left.select_nodes(l.clone())?; + let rest = my_right.select_nodes(r.clone())?; + Ok(NodeSel::Cons(first, rest)) + } else { + Err(E::from((s.loc(), "not a cons".to_string()))) + } + } +} diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 85741c97f..b728e2443 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1196,9 +1196,10 @@ fn test_inline_out_of_bounds_diagnostic() { #[test] fn test_defmac_basic_0() { let prog = indoc! {" - (defmac double-arg (A) (list (concat A \"1\") (concat A \"2\"))) - (mod (double-arg X) - (+ X1 X2) + (mod (X) + (defmac double-arg (A) (list (concat A (string->symbol \"1\")) (concat A (string->symbol \"2\")))) + (defun strange (double-arg X) (+ X1 X2)) + (strange X (* 2 X)) ) "} .to_string(); From d88d1740fb2cf90b320b26c232085b1c19db8d4a Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 10 Mar 2023 12:03:18 -0800 Subject: [PATCH 024/196] Working smoke test, many issues sorted out. We should probably delay reifying the macro arguments for defmac invocations until we know the extension wants to handle this call, will do that. --- src/compiler/comptypes.rs | 1 + src/compiler/evaluate.rs | 14 +++- src/compiler/preprocessor.rs | 113 +++++++++++++++++++++++++-------- src/tests/compiler/compiler.rs | 6 +- 4 files changed, 102 insertions(+), 32 deletions(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index ad3015f5c..77c5b5df6 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -579,3 +579,4 @@ pub fn join_vecs_to_string(sep: Vec, vecs: &[Vec]) -> String { decode_string(&s) } + diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 8f4a1cc18..6bdacfdfb 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -703,13 +703,25 @@ impl<'info> Evaluator { let compiled_borrowed: &SExp = compiled.borrow(); Ok(Rc::new(BodyForm::Quoted(compiled_borrowed.clone()))) } else { + let mut converted_args = Vec::new(); + for a in arguments_to_convert.iter() { + let shrunk = self.shrink_bodyform_visited( + allocator, + visited, + prog_args.clone(), + env, + a.clone(), + only_inline, + )?; + converted_args.push(shrunk); + } for ext in self.extensions.iter() { if let Some(res) = ext.try_eval( self, env, &l, call_name, - arguments_to_convert, + &converted_args, body.clone() )? { return Ok(res); diff --git a/src/compiler/preprocessor.rs b/src/compiler/preprocessor.rs index 32b96e98e..b29af42ec 100644 --- a/src/compiler/preprocessor.rs +++ b/src/compiler/preprocessor.rs @@ -20,6 +20,29 @@ struct Preprocessor { helpers: Vec, } +// If the bodyform represents a constant, only match a quoted string. +fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { + if let BodyForm::Quoted(SExp::QuotedString(al,_,an)) = body.borrow() { + Ok(Some((al.clone(),an.clone()))) + } else if let BodyForm::Value(SExp::QuotedString(al,_,an)) = body.borrow() { + Ok(Some((al.clone(),an.clone()))) + } else if let BodyForm::Quoted(_) = body.borrow() { + Err(CompileErr(body.loc(), "string required".to_string())) + } else { + Ok(None) + } +} + +fn match_atom(body: Rc) -> Result)>, CompileErr> { + if let BodyForm::Quoted(SExp::Atom(al,an)) = body.borrow() { + Ok(Some((al.clone(),an.clone()))) + } else if let BodyForm::Quoted(_) = body.borrow() { + Err(CompileErr(body.loc(), "atom required".to_string())) + } else { + Ok(None) + } +} + struct PreprocessorExtension { } impl EvalExtension for PreprocessorExtension { fn try_eval( @@ -36,17 +59,38 @@ impl EvalExtension for PreprocessorExtension { return Err(CompileErr(loc.clone(), "string->symbol needs 1 argument".to_string())); } - eprintln!("args[0] {}", args[0].to_sexp()); + if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - if let BodyForm::Quoted(SExp::QuotedString(al,_,an)) = args[0].borrow() { - return Ok(Some(Rc::new(BodyForm::Quoted(SExp::Atom(al.clone(),an.clone()))))); - } else if let BodyForm::Quoted(x) = args[0].borrow() { - return Err(CompileErr(loc.clone(), "string->symbol takes a string".to_string())); + return Ok(Some(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value))))); + } else { + eprintln!("pp helper returned {}", decode_string(name)); + return Ok(Some(body.clone())); + } + } else if name == b"symbol->string" { + if let Some((loc, value)) = match_atom(args[0].clone())? { + return Ok(Some(Rc::new(BodyForm::Quoted(SExp::QuotedString(loc,b'\"',value))))); } else { + eprintln!("pp helper returned {}", decode_string(name)); return Ok(Some(body.clone())); } + } else if name == b"string-append" { + let mut out_vec = Vec::new(); + let mut out_loc = None; + for a in args.iter() { + if let Some((loc, mut value)) = match_quoted_string(a.clone())? { + if out_loc.is_none() { + out_loc = Some(loc); + } + out_vec.append(&mut value); + } else { + eprintln!("pp helper returned {}", decode_string(name)); + return Ok(Some(body.clone())); + } + } + return Ok(Some(Rc::new(BodyForm::Quoted(SExp::QuotedString(out_loc.unwrap_or_else(|| body.loc()),b'\"',out_vec))))); } + eprintln!("pp helper didn't handle {}", decode_string(name)); Ok(None) } } @@ -130,10 +174,10 @@ impl Preprocessor { // First expand inner macros. let first_expanded = self.expand_macros(f.clone())?; let rest_expanded = self.expand_macros(r.clone())?; - let new_self = SExp::Cons(l.clone(), first_expanded, rest_expanded); + let new_self = Rc::new(SExp::Cons(l.clone(), first_expanded, rest_expanded)); if let Ok(NodeSel::Cons((nl, name), args)) = NodeSel::Cons( Atom::Here(()), ThisNode::Here - ).select_nodes(body.clone()) { + ).select_nodes(new_self.clone()) { // See if it's a form that calls one of our macros. for m in self.helpers.iter() { eprintln!("want {} helper {}", decode_string(&name), m.to_sexp()); @@ -142,6 +186,11 @@ impl Preprocessor { continue; } + eprintln!("expanding macro {}", m.to_sexp()); + for h in self.helpers.iter() { + eprintln!("- {}", decode_string(h.name())); + } + // as inline defuns because they're closest to that // semantically. let mut allocator = Allocator::new(); @@ -165,14 +214,14 @@ impl Preprocessor { None )?; - eprintln!("shrink res {}", res.to_sexp()); - if let Ok(unquoted) = dequote(body.loc(), res) { return Ok(unquoted); } } } } + + return Ok(new_self); } Ok(body) @@ -185,35 +234,43 @@ impl Preprocessor { ) -> Result, CompileErr> { eprintln!("decode_macro {definition}"); if let Ok(NodeSel::Cons( - defmac_loc, + (defmac_loc, kw), NodeSel::Cons( (nl, name), NodeSel::Cons(args,body) ) )) = NodeSel::Cons( - Atom::Here("defmac"), + Atom::Here(()), NodeSel::Cons( Atom::Here(()), NodeSel::Cons(ThisNode::Here, ThisNode::Here) ) ).select_nodes(definition.clone()) { - let target_defun = Rc::new(SExp::Cons( - defmac_loc.clone(), - Rc::new(SExp::atom_from_string(defmac_loc.clone(), "defun")), - Rc::new(SExp::Cons( - nl.clone(), - Rc::new(SExp::Atom(nl.clone(), name.clone())), - Rc::new(SExp::Cons( - args.loc(), args.clone(), body.clone() - )) - )) - )); - eprintln!("target_defun {target_defun}"); - if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { - self.evaluator.add_helper(&helper); - self.helpers.push(helper); - } else { - return Err(CompileErr(definition.loc(), "defmac found but couldn't be converted to function".to_string())); + let is_defmac = kw == b"defmac"; + if is_defmac || kw == b"defmacro" || kw == b"defun" || kw == b"defun-inline" || kw == b"defconst" || kw == b"defconstant" { + if is_defmac { + let target_defun = Rc::new(SExp::Cons( + defmac_loc.clone(), + Rc::new(SExp::atom_from_string(defmac_loc.clone(), "defun")), + Rc::new(SExp::Cons( + nl.clone(), + Rc::new(SExp::Atom(nl.clone(), name.clone())), + Rc::new(SExp::Cons( + args.loc(), args.clone(), body.clone() + )) + )) + )); + eprintln!("target_defun {target_defun}"); + if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { + eprintln!("add helper {}", helper.to_sexp()); + self.evaluator.add_helper(&helper); + self.helpers.push(helper); + } else { + return Err(CompileErr(definition.loc(), "defmac found but couldn't be converted to function".to_string())); + } + } else if let Some(helper) = compile_helperform(self.opts.clone(), definition)? { + self.evaluator.add_helper(&helper); + } } } diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index b728e2443..9091ff376 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1197,12 +1197,12 @@ fn test_inline_out_of_bounds_diagnostic() { fn test_defmac_basic_0() { let prog = indoc! {" (mod (X) - (defmac double-arg (A) (list (concat A (string->symbol \"1\")) (concat A (string->symbol \"2\")))) + (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) \"2\")))) (defun strange (double-arg X) (+ X1 X2)) (strange X (* 2 X)) ) "} .to_string(); - let res = run_string(&prog, &"(3 4)".to_string()).unwrap(); - assert_eq!(res.to_string(), "7"); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "9"); } From 7f99755ac71668b3e5ad96c053e78e4800b498a4 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 10 Mar 2023 12:15:05 -0800 Subject: [PATCH 025/196] String operations require strings, not other kinds of atoms --- src/tests/compiler/compiler.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 9091ff376..833d1fe00 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1202,7 +1202,37 @@ fn test_defmac_basic_0() { (strange X (* 2 X)) ) "} - .to_string(); + .to_string(); let res = run_string(&prog, &"(3)".to_string()).unwrap(); assert_eq!(res.to_string(), "9"); } + +#[test] +fn test_defmac_basic_shared_constant() { + let prog = indoc! {" + (mod (X) + (defconstant twostring \"2\") + (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) twostring)))) + (defun strange (double-arg X) (+ X1 X2)) + (c twostring (strange X (* 2 X))) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(\"2\" . 9)"); +} + +#[test] +fn test_defmac_basic_shared_constant_not_string_with_string_operator() { + let prog = indoc! {" + (mod (X) + (defconstant twostring 2) + (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) twostring)))) + (defun strange (double-arg X) (+ X1 X2)) + (c twostring (strange X (* 2 X))) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()); + assert!(res.is_err()); +} From 9698c94ffa3f5abdc76aaff7f06ad6e78bb3f149 Mon Sep 17 00:00:00 2001 From: arty Date: Sun, 12 Mar 2023 14:33:54 -0700 Subject: [PATCH 026/196] Move argument downstream of the extension, making it controllable and moving it out of the main path which is currently well tuned --- src/compiler/evaluate.rs | 16 +++--------- src/compiler/preprocessor.rs | 49 ++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 6bdacfdfb..cbbb6faa3 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -74,6 +74,7 @@ pub trait EvalExtension { fn try_eval( &self, evaluator: &Evaluator, + prog_args: Rc, env: &HashMap, Rc>, loc: &Srcloc, name: &[u8], @@ -703,25 +704,14 @@ impl<'info> Evaluator { let compiled_borrowed: &SExp = compiled.borrow(); Ok(Rc::new(BodyForm::Quoted(compiled_borrowed.clone()))) } else { - let mut converted_args = Vec::new(); - for a in arguments_to_convert.iter() { - let shrunk = self.shrink_bodyform_visited( - allocator, - visited, - prog_args.clone(), - env, - a.clone(), - only_inline, - )?; - converted_args.push(shrunk); - } for ext in self.extensions.iter() { if let Some(res) = ext.try_eval( self, + prog_args.clone(), env, &l, call_name, - &converted_args, + &arguments_to_convert, body.clone() )? { return Ok(res); diff --git a/src/compiler/preprocessor.rs b/src/compiler/preprocessor.rs index b29af42ec..165087e6e 100644 --- a/src/compiler/preprocessor.rs +++ b/src/compiler/preprocessor.rs @@ -43,22 +43,53 @@ fn match_atom(body: Rc) -> Result)>, CompileEr } } +fn reify_args( + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + args: &[Rc] +) -> Result>, CompileErr> { + let mut allocator = Allocator::new(); + let mut converted_args = Vec::new(); + for a in args.iter() { + let shrunk = evaluator.shrink_bodyform( + &mut allocator, + prog_args.clone(), + env, + a.clone(), + false, + None + )?; + converted_args.push(shrunk); + } + Ok(converted_args) +} + struct PreprocessorExtension { } impl EvalExtension for PreprocessorExtension { fn try_eval( &self, evaluator: &Evaluator, + prog_args: Rc, env: &HashMap, Rc>, loc: &Srcloc, name: &[u8], - args: &[Rc], + raw_args: &[Rc], body: Rc, ) -> Result>, CompileErr> { if name == b"string->symbol" { - if args.len() != 1 { + if raw_args.len() != 1 { return Err(CompileErr(loc.clone(), "string->symbol needs 1 argument".to_string())); } + let args = reify_args( + evaluator, + prog_args, + env, + loc, + raw_args + )?; if let Some((loc, value)) = match_quoted_string(args[0].clone())? { return Ok(Some(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value))))); @@ -67,6 +98,13 @@ impl EvalExtension for PreprocessorExtension { return Ok(Some(body.clone())); } } else if name == b"symbol->string" { + let args = reify_args( + evaluator, + prog_args, + env, + loc, + raw_args + )?; if let Some((loc, value)) = match_atom(args[0].clone())? { return Ok(Some(Rc::new(BodyForm::Quoted(SExp::QuotedString(loc,b'\"',value))))); } else { @@ -74,6 +112,13 @@ impl EvalExtension for PreprocessorExtension { return Ok(Some(body.clone())); } } else if name == b"string-append" { + let args = reify_args( + evaluator, + prog_args, + env, + loc, + raw_args + )?; let mut out_vec = Vec::new(); let mut out_loc = None; for a in args.iter() { From 1209065af3753916dc1dd028c11931a37cab5226 Mon Sep 17 00:00:00 2001 From: arty Date: Sun, 12 Mar 2023 18:31:33 -0700 Subject: [PATCH 027/196] Break out functions into individual containers, reify arguments in one place --- src/compiler/preprocessor.rs | 198 ++++++++++++++++++++++++++--------- 1 file changed, 147 insertions(+), 51 deletions(-) diff --git a/src/compiler/preprocessor.rs b/src/compiler/preprocessor.rs index 165087e6e..a228ce6c7 100644 --- a/src/compiler/preprocessor.rs +++ b/src/compiler/preprocessor.rs @@ -66,8 +66,8 @@ fn reify_args( Ok(converted_args) } -struct PreprocessorExtension { } -impl EvalExtension for PreprocessorExtension { +/// A function to evaluate in preprocessor macros. +trait ExtensionFunction { fn try_eval( &self, evaluator: &Evaluator, @@ -75,75 +75,171 @@ impl EvalExtension for PreprocessorExtension { env: &HashMap, Rc>, loc: &Srcloc, name: &[u8], - raw_args: &[Rc], + args: &[Rc], body: Rc, - ) -> Result>, CompileErr> { - if name == b"string->symbol" { - if raw_args.len() != 1 { - return Err(CompileErr(loc.clone(), "string->symbol needs 1 argument".to_string())); - } + ) -> Result, CompileErr>; +} - let args = reify_args( - evaluator, - prog_args, - env, - loc, - raw_args - )?; - if let Some((loc, value)) = match_quoted_string(args[0].clone())? { +struct SymbolToString { } + +impl SymbolToString { + fn new() -> Rc { Rc::new(SymbolToString { }) } +} + +impl ExtensionFunction for SymbolToString { + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + if let Some((loc, value)) = match_atom(args[0].clone())? { + return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(loc,b'\"',value)))); + } else { + return Ok(body.clone()); + } + } +} + +struct StringToSymbol { } + +impl StringToSymbol { + fn new() -> Rc { Rc::new(StringToSymbol { }) } +} + +impl ExtensionFunction for StringToSymbol { + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + if let Some((loc, value)) = match_quoted_string(args[0].clone())? { + return Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value)))); + } else { + eprintln!("pp helper returned {}", decode_string(name)); + return Ok(body.clone()); + } + } +} + +struct StringAppend { } + +impl StringAppend { + fn new() -> Rc { Rc::new(StringAppend { }) } +} - return Ok(Some(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value))))); +impl ExtensionFunction for StringAppend { + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + let mut out_vec = Vec::new(); + let mut out_loc = None; + for a in args.iter() { + if let Some((loc, mut value)) = match_quoted_string(a.clone())? { + if out_loc.is_none() { + out_loc = Some(loc); + } + out_vec.append(&mut value); } else { eprintln!("pp helper returned {}", decode_string(name)); - return Ok(Some(body.clone())); + return Ok(body.clone()); } - } else if name == b"symbol->string" { + } + return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(out_loc.unwrap_or_else(|| body.loc()),b'\"',out_vec)))); + } +} + +/// An evaluator extension for the preprocessor. +/// +/// Implements scheme like conversion functions for handling chialisp programs and +/// bits of them. +/// +/// These functions are provided: +/// +/// Basic conversion +/// +/// string->symbol +/// symbol->string +/// string->number +/// number->string +/// +/// Generate fresh symbols +/// +/// gensym +/// +/// Working with values +/// +/// string-append s0 s1 ... +/// substring s start end +/// first +/// rest +/// cons +struct PreprocessorExtension { + extfuns: HashMap, Rc> +} + +impl PreprocessorExtension { + fn new() -> Self { + let extfuns = [ + (b"string->symbol".to_vec(), StringToSymbol::new()), + (b"symbol->string".to_vec(), SymbolToString::new()), + (b"string-append".to_vec(), StringAppend::new()), + ]; + PreprocessorExtension { extfuns: HashMap::from(extfuns) } + } +} + +impl EvalExtension for PreprocessorExtension { + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + raw_args: &[Rc], + body: Rc, + ) -> Result>, CompileErr> { + if let Some(extfun) = self.extfuns.get(name) { + eprintln!("try function {}", decode_string(name)); let args = reify_args( evaluator, - prog_args, + prog_args.clone(), env, loc, raw_args )?; - if let Some((loc, value)) = match_atom(args[0].clone())? { - return Ok(Some(Rc::new(BodyForm::Quoted(SExp::QuotedString(loc,b'\"',value))))); - } else { - eprintln!("pp helper returned {}", decode_string(name)); - return Ok(Some(body.clone())); - } - } else if name == b"string-append" { - let args = reify_args( + Ok(Some(extfun.try_eval( evaluator, prog_args, env, loc, - raw_args - )?; - let mut out_vec = Vec::new(); - let mut out_loc = None; - for a in args.iter() { - if let Some((loc, mut value)) = match_quoted_string(a.clone())? { - if out_loc.is_none() { - out_loc = Some(loc); - } - out_vec.append(&mut value); - } else { - eprintln!("pp helper returned {}", decode_string(name)); - return Ok(Some(body.clone())); - } - } - return Ok(Some(Rc::new(BodyForm::Quoted(SExp::QuotedString(out_loc.unwrap_or_else(|| body.loc()),b'\"',out_vec))))); + name, + &args, + body + )?)) + } else { + Ok(None) } - - eprintln!("pp helper didn't handle {}", decode_string(name)); - Ok(None) } } -impl PreprocessorExtension { - fn new() -> Self { PreprocessorExtension { } } -} - impl Preprocessor { pub fn new(opts: Rc) -> Self { let runner = Rc::new(DefaultProgramRunner::new()); From d96d8c21faca3c6b53b4df67953cc4bf641fe117 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 13 Mar 2023 08:21:05 -0700 Subject: [PATCH 028/196] Adding predicates and more functions from scheme --- src/compiler/preprocessor/macros.rs | 416 ++++++++++++++++++ .../{preprocessor.rs => preprocessor/mod.rs} | 225 +--------- src/compiler/sexp.rs | 2 +- src/tests/compiler/compiler.rs | 46 +- src/tests/compiler/mod.rs | 1 + src/tests/compiler/preprocessor.rs | 97 ++++ 6 files changed, 520 insertions(+), 267 deletions(-) create mode 100644 src/compiler/preprocessor/macros.rs rename src/compiler/{preprocessor.rs => preprocessor/mod.rs} (67%) create mode 100644 src/tests/compiler/preprocessor.rs diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs new file mode 100644 index 000000000..6af7d5226 --- /dev/null +++ b/src/compiler/preprocessor/macros.rs @@ -0,0 +1,416 @@ +use std::borrow::Borrow; +use std::collections::HashMap; +use std::rc::Rc; + +use clvmr::allocator::Allocator; + +use crate::classic::clvm::__type_compatibility__::bi_one; + +use crate::compiler::comptypes::{BodyForm, CompileErr}; +use crate::compiler::evaluate::{EvalExtension, Evaluator}; +use crate::compiler::sexp::{SExp, decode_string}; +use crate::compiler::srcloc::{Srcloc}; +use crate::util::{Number, number_from_u8}; + +// If the bodyform represents a constant, only match a quoted string. +fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { + if let BodyForm::Quoted(SExp::QuotedString(al,_,an)) = body.borrow() { + Ok(Some((al.clone(),an.clone()))) + } else if let BodyForm::Value(SExp::QuotedString(al,_,an)) = body.borrow() { + Ok(Some((al.clone(),an.clone()))) + } else if let BodyForm::Quoted(_) = body.borrow() { + Err(CompileErr(body.loc(), "string required".to_string())) + } else { + Ok(None) + } +} + +fn match_atom(body: Rc) -> Result)>, CompileErr> { + if let BodyForm::Quoted(SExp::Atom(al,an)) = body.borrow() { + Ok(Some((al.clone(),an.clone()))) + } else if let BodyForm::Quoted(_) = body.borrow() { + Err(CompileErr(body.loc(), "atom required".to_string())) + } else { + Ok(None) + } +} + +enum MatchedNumber { + MatchedInt(Srcloc, Number), + MatchedHex(Srcloc, Vec) +} + +fn match_number(body: Rc) -> Result, CompileErr> { + if let BodyForm::Quoted(SExp::Integer(il,n)) = body.borrow() { + Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))) + } else if let BodyForm::Quoted(SExp::QuotedString(ql,b'x',b)) = body.borrow() { + Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))) + } else if let BodyForm::Quoted(_) = body.borrow() { + Err(CompileErr(body.loc(), "number required".to_string())) + } else { + Ok(None) + } +} + +fn reify_args( + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + args: &[Rc] +) -> Result>, CompileErr> { + let mut allocator = Allocator::new(); + let mut converted_args = Vec::new(); + for a in args.iter() { + let shrunk = evaluator.shrink_bodyform( + &mut allocator, + prog_args.clone(), + env, + a.clone(), + false, + None + )?; + converted_args.push(shrunk); + } + Ok(converted_args) +} + +/// A container for a function to evaluate in advanced preprocessor macros. +/// We use this trait (which is very similar to the extension trait in Evaluator) +/// as a definite handler for a specific named form, so optional returns aren't +/// needed. These are held in a collection and looked up. To be maximally +/// conservative with typing and lifetime, we hold these via Rc. +pub trait ExtensionFunction { + fn required_args(&self) -> Option; + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr>; +} + +struct StringQ { } + +impl StringQ { + fn new() -> Rc { Rc::new(StringQ { }) } +} + +impl ExtensionFunction for StringQ { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + let res = + match match_quoted_string(args[0].clone()) { + Ok(Some(_)) => { + SExp::Integer(loc.clone(), bi_one()) + } + Ok(None) => { + return Ok(body.clone()); + } + Err(_) => { + SExp::Nil(loc.clone()) + } + }; + + Ok(Rc::new(BodyForm::Quoted(res))) + } +} + +struct NumberQ { } + +impl NumberQ { + fn new() -> Rc { Rc::new(NumberQ { }) } +} + +impl ExtensionFunction for NumberQ { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + todo!(); + } +} + +struct SymbolQ { } + +impl SymbolQ { + fn new() -> Rc { Rc::new(SymbolQ { }) } +} + +impl ExtensionFunction for SymbolQ { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + todo!(); + } +} + +struct SymbolToString { } + +impl SymbolToString { + fn new() -> Rc { Rc::new(SymbolToString { }) } +} + +impl ExtensionFunction for SymbolToString { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + if let Some((loc, value)) = match_atom(args[0].clone())? { + return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(loc,b'\"',value)))); + } else { + return Ok(body.clone()); + } + } +} + +struct StringToSymbol { } + +impl StringToSymbol { + fn new() -> Rc { Rc::new(StringToSymbol { }) } +} + +impl ExtensionFunction for StringToSymbol { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + if let Some((loc, value)) = match_quoted_string(args[0].clone())? { + return Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value)))); + } else { + eprintln!("pp helper returned {}", decode_string(name)); + return Ok(body.clone()); + } + } +} + +struct StringAppend { } + +impl StringAppend { + fn new() -> Rc { Rc::new(StringAppend { }) } +} + +impl ExtensionFunction for StringAppend { + fn required_args(&self) -> Option { None } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + let mut out_vec = Vec::new(); + let mut out_loc = None; + for a in args.iter() { + if let Some((loc, mut value)) = match_quoted_string(a.clone())? { + if out_loc.is_none() { + out_loc = Some(loc); + } + out_vec.append(&mut value); + } else { + eprintln!("pp helper returned {}", decode_string(name)); + return Ok(body.clone()); + } + } + return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(out_loc.unwrap_or_else(|| body.loc()),b'\"',out_vec)))); + } +} + +struct NumberToString { } + +impl NumberToString { + fn new() -> Rc { Rc::new(NumberToString { }) } +} + +impl ExtensionFunction for NumberToString { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + let match_res = match_number(args[0].clone())?; + let (use_loc, int_val) = + match &match_res { + Some(MatchedNumber::MatchedInt(l,i)) => { (l.clone(), i.clone()) } + Some(MatchedNumber::MatchedHex(l,h)) => { + (l.clone(), number_from_u8(&h)) + } + _ => { + return Ok(body.clone()); + } + }; + Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(use_loc, b'\"', int_val.to_string().as_bytes().to_vec())))) + } +} + +struct StringToNumber { } + +impl StringToNumber { + fn new() -> Rc { Rc::new(StringToNumber { }) } +} + +impl ExtensionFunction for StringToNumber { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + todo!(); + } +} + +/// An evaluator extension for the preprocessor. +/// +/// Implements scheme like conversion functions for handling chialisp programs and +/// bits of them. +/// +/// These functions are provided: +/// +/// Queries +/// +/// pair? +/// string? +/// number? +/// symbol? +/// +/// Basic conversion +/// +/// string->symbol +/// symbol->string +/// string->number +/// number->string +/// +/// Working with values +/// +/// string-append s0 s1 ... +/// substring s start end +/// first +/// rest +/// cons +pub struct PreprocessorExtension { + extfuns: HashMap, Rc> +} + +impl PreprocessorExtension { + pub fn new() -> Self { + let extfuns = [ + (b"string?".to_vec(), StringQ::new()), + (b"number?".to_vec(), NumberQ::new()), + (b"symbol?".to_vec(), SymbolQ::new()), + + (b"string->symbol".to_vec(), StringToSymbol::new()), + (b"symbol->string".to_vec(), SymbolToString::new()), + (b"string->number".to_vec(), StringToNumber::new()), + (b"number->string".to_vec(), NumberToString::new()), + + (b"string-append".to_vec(), StringAppend::new()), + ]; + PreprocessorExtension { extfuns: HashMap::from(extfuns) } + } +} + +impl EvalExtension for PreprocessorExtension { + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + raw_args: &[Rc], + body: Rc, + ) -> Result>, CompileErr> { + if let Some(extfun) = self.extfuns.get(name) { + if let Some(n) = extfun.required_args() { + if raw_args.len() != n { + return Err(CompileErr(loc.clone(), format!("{} requires {} args", decode_string(name), n))); + } + } + + eprintln!("try function {}", decode_string(name)); + let args = reify_args( + evaluator, + prog_args.clone(), + env, + loc, + raw_args + )?; + Ok(Some(extfun.try_eval( + evaluator, + prog_args, + env, + loc, + name, + &args, + body + )?)) + } else { + Ok(None) + } + } +} diff --git a/src/compiler/preprocessor.rs b/src/compiler/preprocessor/mod.rs similarity index 67% rename from src/compiler/preprocessor.rs rename to src/compiler/preprocessor/mod.rs index a228ce6c7..831851348 100644 --- a/src/compiler/preprocessor.rs +++ b/src/compiler/preprocessor/mod.rs @@ -1,3 +1,5 @@ +mod macros; + use std::borrow::Borrow; use std::collections::HashMap; use std::rc::Rc; @@ -11,8 +13,9 @@ use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HelperForm, use crate::compiler::evaluate::{ArgInputs, create_argument_captures, dequote, EvalExtension, Evaluator}; use crate::compiler::frontend::compile_helperform; use crate::compiler::sexp::{Atom, decode_string, enlist, First, NodeSel, parse_sexp, SelectNode, SExp, ThisNode}; +use crate::compiler::preprocessor::macros::PreprocessorExtension; use crate::compiler::srcloc::Srcloc; -use crate::util::ErrInto; +use crate::util::{ErrInto, Number, number_from_u8}; struct Preprocessor { opts: Rc, @@ -20,226 +23,6 @@ struct Preprocessor { helpers: Vec, } -// If the bodyform represents a constant, only match a quoted string. -fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { - if let BodyForm::Quoted(SExp::QuotedString(al,_,an)) = body.borrow() { - Ok(Some((al.clone(),an.clone()))) - } else if let BodyForm::Value(SExp::QuotedString(al,_,an)) = body.borrow() { - Ok(Some((al.clone(),an.clone()))) - } else if let BodyForm::Quoted(_) = body.borrow() { - Err(CompileErr(body.loc(), "string required".to_string())) - } else { - Ok(None) - } -} - -fn match_atom(body: Rc) -> Result)>, CompileErr> { - if let BodyForm::Quoted(SExp::Atom(al,an)) = body.borrow() { - Ok(Some((al.clone(),an.clone()))) - } else if let BodyForm::Quoted(_) = body.borrow() { - Err(CompileErr(body.loc(), "atom required".to_string())) - } else { - Ok(None) - } -} - -fn reify_args( - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - args: &[Rc] -) -> Result>, CompileErr> { - let mut allocator = Allocator::new(); - let mut converted_args = Vec::new(); - for a in args.iter() { - let shrunk = evaluator.shrink_bodyform( - &mut allocator, - prog_args.clone(), - env, - a.clone(), - false, - None - )?; - converted_args.push(shrunk); - } - Ok(converted_args) -} - -/// A function to evaluate in preprocessor macros. -trait ExtensionFunction { - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr>; -} - -struct SymbolToString { } - -impl SymbolToString { - fn new() -> Rc { Rc::new(SymbolToString { }) } -} - -impl ExtensionFunction for SymbolToString { - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - if let Some((loc, value)) = match_atom(args[0].clone())? { - return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(loc,b'\"',value)))); - } else { - return Ok(body.clone()); - } - } -} - -struct StringToSymbol { } - -impl StringToSymbol { - fn new() -> Rc { Rc::new(StringToSymbol { }) } -} - -impl ExtensionFunction for StringToSymbol { - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - return Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value)))); - } else { - eprintln!("pp helper returned {}", decode_string(name)); - return Ok(body.clone()); - } - } -} - -struct StringAppend { } - -impl StringAppend { - fn new() -> Rc { Rc::new(StringAppend { }) } -} - -impl ExtensionFunction for StringAppend { - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - let mut out_vec = Vec::new(); - let mut out_loc = None; - for a in args.iter() { - if let Some((loc, mut value)) = match_quoted_string(a.clone())? { - if out_loc.is_none() { - out_loc = Some(loc); - } - out_vec.append(&mut value); - } else { - eprintln!("pp helper returned {}", decode_string(name)); - return Ok(body.clone()); - } - } - return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(out_loc.unwrap_or_else(|| body.loc()),b'\"',out_vec)))); - } -} - -/// An evaluator extension for the preprocessor. -/// -/// Implements scheme like conversion functions for handling chialisp programs and -/// bits of them. -/// -/// These functions are provided: -/// -/// Basic conversion -/// -/// string->symbol -/// symbol->string -/// string->number -/// number->string -/// -/// Generate fresh symbols -/// -/// gensym -/// -/// Working with values -/// -/// string-append s0 s1 ... -/// substring s start end -/// first -/// rest -/// cons -struct PreprocessorExtension { - extfuns: HashMap, Rc> -} - -impl PreprocessorExtension { - fn new() -> Self { - let extfuns = [ - (b"string->symbol".to_vec(), StringToSymbol::new()), - (b"symbol->string".to_vec(), SymbolToString::new()), - (b"string-append".to_vec(), StringAppend::new()), - ]; - PreprocessorExtension { extfuns: HashMap::from(extfuns) } - } -} - -impl EvalExtension for PreprocessorExtension { - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], - raw_args: &[Rc], - body: Rc, - ) -> Result>, CompileErr> { - if let Some(extfun) = self.extfuns.get(name) { - eprintln!("try function {}", decode_string(name)); - let args = reify_args( - evaluator, - prog_args.clone(), - env, - loc, - raw_args - )?; - Ok(Some(extfun.try_eval( - evaluator, - prog_args, - env, - loc, - name, - &args, - body - )?)) - } else { - Ok(None) - } - } -} - impl Preprocessor { pub fn new(opts: Rc) -> Self { let runner = Rc::new(DefaultProgramRunner::new()); diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index f593754a3..d01104085 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -264,7 +264,7 @@ fn normalize_int(v: Vec, base: u32) -> Number { fn from_hex(l: Srcloc, v: &[u8]) -> SExp { let mut result = vec![0; (v.len() - 2) / 2]; hex2bin(&v[2..], &mut result).expect("should convert from hex"); - SExp::QuotedString(l, b'"', result) + SExp::QuotedString(l, b'x', result) } fn make_atom(l: Srcloc, v: Vec) -> SExp { diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 833d1fe00..e4883706b 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -58,7 +58,7 @@ fn run_string_maybe_opt( }) } -fn run_string(content: &String, args: &String) -> Result, CompileErr> { +pub fn run_string(content: &String, args: &String) -> Result, CompileErr> { run_string_maybe_opt(content, args, false) } @@ -1192,47 +1192,3 @@ fn test_inline_out_of_bounds_diagnostic() { assert!(false); } } - -#[test] -fn test_defmac_basic_0() { - let prog = indoc! {" - (mod (X) - (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) \"2\")))) - (defun strange (double-arg X) (+ X1 X2)) - (strange X (* 2 X)) - ) - "} - .to_string(); - let res = run_string(&prog, &"(3)".to_string()).unwrap(); - assert_eq!(res.to_string(), "9"); -} - -#[test] -fn test_defmac_basic_shared_constant() { - let prog = indoc! {" - (mod (X) - (defconstant twostring \"2\") - (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) twostring)))) - (defun strange (double-arg X) (+ X1 X2)) - (c twostring (strange X (* 2 X))) - ) - "} - .to_string(); - let res = run_string(&prog, &"(3)".to_string()).unwrap(); - assert_eq!(res.to_string(), "(\"2\" . 9)"); -} - -#[test] -fn test_defmac_basic_shared_constant_not_string_with_string_operator() { - let prog = indoc! {" - (mod (X) - (defconstant twostring 2) - (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) twostring)))) - (defun strange (double-arg X) (+ X1 X2)) - (c twostring (strange X (* 2 X))) - ) - "} - .to_string(); - let res = run_string(&prog, &"(3)".to_string()); - assert!(res.is_err()); -} diff --git a/src/tests/compiler/mod.rs b/src/tests/compiler/mod.rs index 09b9beff2..dfb8e6edc 100644 --- a/src/tests/compiler/mod.rs +++ b/src/tests/compiler/mod.rs @@ -7,6 +7,7 @@ use crate::compiler::srcloc::{Srcloc, Until}; mod clvm; mod compiler; mod evaluate; +mod preprocessor; mod repl; mod srcloc; mod usecheck; diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs new file mode 100644 index 000000000..6605e4f9a --- /dev/null +++ b/src/tests/compiler/preprocessor.rs @@ -0,0 +1,97 @@ +use crate::tests::compiler::compiler::run_string; + +#[test] +fn test_defmac_basic_0() { + let prog = indoc! {" + (mod (X) + (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) \"2\")))) + (defun strange (double-arg X) (+ X1 X2)) + (strange X (* 2 X)) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "9"); +} + +#[test] +fn test_defmac_basic_shared_constant() { + let prog = indoc! {" + (mod (X) + (defconstant twostring \"2\") + (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) twostring)))) + (defun strange (double-arg X) (+ X1 X2)) + (c twostring (strange X (* 2 X))) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(\"2\" . 9)"); +} + +#[test] +fn test_defmac_basic_shared_constant_not_string_with_string_operator() { + let prog = indoc! {" + (mod (X) + (defconstant twostring 2) + (defmac double-arg (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) twostring)))) + (defun strange (double-arg X) (+ X1 X2)) + (c twostring (strange X (* 2 X))) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()); + assert!(res.is_err()); +} + +#[test] +fn test_defmac_basic_shared_constant_not_string_with_string_operator_fun() { + let prog = indoc! {" + (mod (X) + (defconstant twostring \"2\") + (defun make-arg-list (A) (list (string->symbol (string-append (symbol->string A) \"1\")) (string->symbol (string-append (symbol->string A) twostring)))) + (defmac double-arg (A) (make-arg-list A)) + (defun strange (double-arg X) (+ X1 X2)) + (c twostring (strange X (* 2 X))) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(\"2\" . 9)"); +} + +#[test] +fn test_defmac_basic_test_is_string_pos() { + let prog = indoc! {" + (mod (X) + (defmac classify (S) + (if (string? S) + (qq (c 1 (unquote S))) + (qq (c 2 (unquote S))) + ) + ) + (c X (classify \"test\")) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(3 1 . \"test\")"); +} + +#[test] +fn test_defmac_basic_test_is_string_neg() { + let prog = indoc! {" + (mod (X) + (defmac classify (S) + (if (string? S) + (qq (c 1 (unquote S))) + (qq (c 2 (unquote S))) + ) + ) + (c X (classify test)) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(3 2 . test)"); +} From 7b65fe624a897ee52b0b93fe60a8f9ecb17f63eb Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 13 Mar 2023 08:38:10 -0700 Subject: [PATCH 029/196] More tests --- src/compiler/preprocessor/macros.rs | 62 +++++++++++++++++++++---- src/tests/compiler/preprocessor.rs | 72 +++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 9 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 6af7d5226..490244e77 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -14,14 +14,32 @@ use crate::util::{Number, number_from_u8}; // If the bodyform represents a constant, only match a quoted string. fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { - if let BodyForm::Quoted(SExp::QuotedString(al,_,an)) = body.borrow() { - Ok(Some((al.clone(),an.clone()))) - } else if let BodyForm::Value(SExp::QuotedString(al,_,an)) = body.borrow() { - Ok(Some((al.clone(),an.clone()))) - } else if let BodyForm::Quoted(_) = body.borrow() { - Err(CompileErr(body.loc(), "string required".to_string())) + let is_string = + match body.borrow() { + BodyForm::Quoted(SExp::QuotedString(al,b'x',an)) => { + None + } + BodyForm::Quoted(SExp::QuotedString(al,_,an)) => { + Some((al.clone(), an.clone())) + } + BodyForm::Value(SExp::QuotedString(al,b'x',an)) => { + None + } + BodyForm::Value(SExp::QuotedString(al,_,an)) => { + Some((al.clone(), an.clone())) + } + BodyForm::Quoted(_) => { + None + } + _ => { + return Ok(None); + } + }; + + if let Some((loc, s)) = is_string { + Ok(Some((loc, s))) } else { - Ok(None) + Err(CompileErr(body.loc(), "string required".to_string())) } } @@ -149,7 +167,20 @@ impl ExtensionFunction for NumberQ { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - todo!(); + let res = + match match_number(args[0].clone()) { + Ok(Some(_)) => { + SExp::Integer(loc.clone(), bi_one()) + } + Ok(None) => { + return Ok(body.clone()); + } + Err(_) => { + SExp::Nil(loc.clone()) + } + }; + + Ok(Rc::new(BodyForm::Quoted(res))) } } @@ -172,7 +203,20 @@ impl ExtensionFunction for SymbolQ { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - todo!(); + let res = + match match_atom(args[0].clone()) { + Ok(Some(_)) => { + SExp::Integer(loc.clone(), bi_one()) + } + Ok(None) => { + return Ok(body.clone()); + } + Err(_) => { + SExp::Nil(loc.clone()) + } + }; + + Ok(Rc::new(BodyForm::Quoted(res))) } } diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 6605e4f9a..45bd15f6c 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -95,3 +95,75 @@ fn test_defmac_basic_test_is_string_neg() { let res = run_string(&prog, &"(3)".to_string()).unwrap(); assert_eq!(res.to_string(), "(3 2 . test)"); } + +#[test] +fn test_defmac_basic_test_is_symbol_pos() { + let prog = indoc! {" + (mod (X) + (defmac classify (S) + (if (symbol? S) + (qq (c 1 (unquote S))) + (qq (c 2 (unquote S))) + ) + ) + (c X (classify test)) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(3 1 . test)"); +} + +#[test] +fn test_defmac_basic_test_is_symbol_neg() { + let prog = indoc! {" + (mod (X) + (defmac classify (S) + (if (symbol? S) + (qq (c 1 (unquote S))) + (qq (c 2 (unquote S))) + ) + ) + (c X (classify \"test\")) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(3 2 . \"test\")"); +} + +#[test] +fn test_defmac_basic_test_is_number_pos() { + let prog = indoc! {" + (mod (X) + (defmac classify (S) + (if (number? S) + (qq (c 1 (unquote S))) + (qq (c 2 (unquote S))) + ) + ) + (c X (classify 7)) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(3 1 . 7)"); +} + +#[test] +fn test_defmac_basic_test_is_number_neg() { + let prog = indoc! {" + (mod (X) + (defmac classify (S) + (if (number? S) + (qq (c 1 (unquote S))) + (qq (c 2 (unquote S))) + ) + ) + (c X (classify \"test\")) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(3 2 . \"test\")"); +} From 397f481aa31b2d9facf65a60def7654621af5ad3 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 13 Mar 2023 13:37:15 -0700 Subject: [PATCH 030/196] WIP, getting there --- src/compiler/preprocessor/macros.rs | 24 +++++++++ src/tests/compiler/preprocessor.rs | 79 +++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 490244e77..5e23bfde2 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -368,6 +368,29 @@ impl ExtensionFunction for StringToNumber { } } +struct Substring { } + +impl Substring { + fn new() -> Rc { Rc::new(Substring { }) } +} + +impl ExtensionFunction for Substring { + fn required_args(&self) -> Option { Some(3) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + todo!(); + } +} + /// An evaluator extension for the preprocessor. /// /// Implements scheme like conversion functions for handling chialisp programs and @@ -413,6 +436,7 @@ impl PreprocessorExtension { (b"number->string".to_vec(), NumberToString::new()), (b"string-append".to_vec(), StringAppend::new()), + (b"substring".to_vec(), Substring::new()), ]; PreprocessorExtension { extfuns: HashMap::from(extfuns) } } diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 45bd15f6c..a4ff430fc 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -167,3 +167,82 @@ fn test_defmac_basic_test_is_number_neg() { let res = run_string(&prog, &"(3)".to_string()).unwrap(); assert_eq!(res.to_string(), "(3 2 . \"test\")"); } + +#[test] +fn test_defmac_create_cond_form() { + let prog = indoc! {" + ;; Make a simple list match ala ocaml/elm/haskell. + ;; + ;; The real version will be more elaborate. This is a test case and a demo. + (mod (X) + (defun list-nth (L N) + (if N + (list-nth (r L) (- N 1)) + (f L) + ) + ) + + (defun list-len (L N) + (if L + (list-len (r L) (+ N 1)) + N + ) + ) + + ;; From a list of bindings or constants, build a matcher for the elements. + (defun gather-bindings-list (expr tomatch) + (if (not expr) + () + () + ) + ) + + (defun gather-bindings (condition expr rest) + (qq + (if (= (list-len (unquote expr)) (unquote (list-len condition))) + (unquote + (let* + ( + (bindings-and-checks (gather-bindings-and-checks condition expr)) + (bindings (f bindings-and-checks)) + (checks (r bindings-and-checks)) + ) + (qq (if checks (let bindings rest))) + ) + ) + () + ) + ) + ) + + ;; For each pair, emit an expression that checks for the requested pattern + ;; and returns either the requested result or allows the following matchers + ;; to run. + (defun handle-matches (expr matches) + (if (not matches) + (qq (x (unquote expr))) + (let + ( + (condition (f (f expr))) + (code (f (r (f expr)))) + ) + (qq (if (unquote (make-match-expr condition expr)) (unquote code) (unquote (handle-matches (r matches))))) + ) + ) + ) + + ;; match as below. + (defmac match (expr . matches) (handle-matches expr matches)) + + (match X + ((16 x y) (c 1 (+ x y))) + ((3 () b c) c) + ((3 (q . 1) b c) b) + (x x) + ) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3 () 1001 1002)".to_string()).unwrap(); + assert_eq!(res.to_string(), "1002"); +} From cd148b7a98e79efcddbafd84b42ebdc00bb976c0 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 14 Mar 2023 14:39:35 -0700 Subject: [PATCH 031/196] WIP, getting there --- src/compiler/evaluate.rs | 28 +++--- src/compiler/preprocessor/macros.rs | 137 ++++++++++++++++++++++--- src/compiler/preprocessor/mod.rs | 6 +- src/tests/compiler/preprocessor.rs | 148 +++++++++++++++++++++------- 4 files changed, 258 insertions(+), 61 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index cbbb6faa3..7d53e8a2c 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -704,20 +704,6 @@ impl<'info> Evaluator { let compiled_borrowed: &SExp = compiled.borrow(); Ok(Rc::new(BodyForm::Quoted(compiled_borrowed.clone()))) } else { - for ext in self.extensions.iter() { - if let Some(res) = ext.try_eval( - self, - prog_args.clone(), - env, - &l, - call_name, - &arguments_to_convert, - body.clone() - )? { - return Ok(res); - } - } - let pres = self .lookup_prim(l.clone(), call_name) .map(|prim| { @@ -910,6 +896,20 @@ impl<'info> Evaluator { env: &HashMap, Rc>, only_inline: bool, ) -> Result, CompileErr> { + for ext in self.extensions.iter() { + if let Some(res) = ext.try_eval( + self, + prog_args.clone(), + env, + &l, + call_name, + &arguments_to_convert, + body.clone() + )? { + return Ok(res); + } + } + let helper = select_helper(&self.helpers, call_name); match helper { Some(HelperForm::Defmacro(mac)) => self.invoke_macro_expansion( diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 5e23bfde2..8aea3ccfc 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -6,8 +6,10 @@ use clvmr::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::bi_one; +use crate::compiler::clvm::truthy; use crate::compiler::comptypes::{BodyForm, CompileErr}; use crate::compiler::evaluate::{EvalExtension, Evaluator}; +use crate::compiler::preprocessor::dequote; use crate::compiler::sexp::{SExp, decode_string}; use crate::compiler::srcloc::{Srcloc}; use crate::util::{Number, number_from_u8}; @@ -80,6 +82,10 @@ fn reify_args( let mut allocator = Allocator::new(); let mut converted_args = Vec::new(); for a in args.iter() { + eprintln!("shrink {}", a.to_sexp()); + for (n,e) in env.iter() { + eprintln!("- {} = {}", decode_string(&n), e.to_sexp()); + } let shrunk = evaluator.shrink_bodyform( &mut allocator, prog_args.clone(), @@ -99,6 +105,7 @@ fn reify_args( /// needed. These are held in a collection and looked up. To be maximally /// conservative with typing and lifetime, we hold these via Rc. pub trait ExtensionFunction { + fn want_interp(&self) -> bool { true } fn required_args(&self) -> Option; fn try_eval( &self, @@ -391,6 +398,109 @@ impl ExtensionFunction for Substring { } } +struct List { } + +impl List { + fn new() -> Rc { Rc::new(List { }) } +} + +impl ExtensionFunction for List { + fn required_args(&self) -> Option { None } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + let mut res = SExp::Nil(loc.clone()); + for (n,e) in env.iter() { + eprintln!("- {} = {}", decode_string(&n), e.to_sexp()); + } + for a in args.iter().rev() { + eprintln!("list arg {}", a.to_sexp()); + if let Ok(unquoted) = dequote(loc.clone(), a.clone()) { + res = SExp::Cons( + loc.clone(), + unquoted, + Rc::new(res) + ); + } else { + return Ok(body.clone()); + } + } + let list_res = BodyForm::Quoted(res); + eprintln!("list_res {}", list_res.to_sexp()); + Ok(Rc::new(list_res)) + } +} + +struct If { } + +impl If { + fn new() -> Rc { Rc::new(If { }) } +} + +impl ExtensionFunction for If { + fn want_interp(&self) -> bool { false } + + fn required_args(&self) -> Option { Some(3) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + let mut allocator = Allocator::new(); + let cond_result = + evaluator.shrink_bodyform( + &mut allocator, + prog_args.clone(), + env, + args[0].clone(), + false, + None + )?; + + if let Ok(unquoted) = dequote(body.loc(), cond_result) { + eprintln!("unquoted {}", unquoted); + if truthy(unquoted) { + eprintln!("truthy, expand {}", args[1].to_sexp()); + evaluator.shrink_bodyform( + &mut allocator, + prog_args.clone(), + env, + args[1].clone(), + false, + None + ) + } else { + eprintln!("falsey, expand {}", args[2].to_sexp()); + evaluator.shrink_bodyform( + &mut allocator, + prog_args.clone(), + env, + args[2].clone(), + false, + None + ) + } + } else { + eprintln!("can't reduce if {}", body.to_sexp()); + Ok(body.clone()) + } + } +} + /// An evaluator extension for the preprocessor. /// /// Implements scheme like conversion functions for handling chialisp programs and @@ -416,9 +526,6 @@ impl ExtensionFunction for Substring { /// /// string-append s0 s1 ... /// substring s start end -/// first -/// rest -/// cons pub struct PreprocessorExtension { extfuns: HashMap, Rc> } @@ -426,6 +533,9 @@ pub struct PreprocessorExtension { impl PreprocessorExtension { pub fn new() -> Self { let extfuns = [ + (b"if".to_vec(), If::new()), + (b"list".to_vec(), List::new()), + (b"string?".to_vec(), StringQ::new()), (b"number?".to_vec(), NumberQ::new()), (b"symbol?".to_vec(), SymbolQ::new()), @@ -460,14 +570,19 @@ impl EvalExtension for PreprocessorExtension { } } - eprintln!("try function {}", decode_string(name)); - let args = reify_args( - evaluator, - prog_args.clone(), - env, - loc, - raw_args - )?; + eprintln!("try function {}", body.to_sexp()); + let args = + if extfun.want_interp() { + reify_args( + evaluator, + prog_args.clone(), + env, + loc, + raw_args + )? + } else { + raw_args.to_vec() + }; Ok(Some(extfun.try_eval( evaluator, prog_args, diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 831851348..3cc3960ed 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -138,8 +138,12 @@ impl Preprocessor { None )?; - if let Ok(unquoted) = dequote(body.loc(), res) { + if let Ok(unquoted) = dequote(body.loc(), res.clone()) { + eprintln!("expand macro {}", unquoted); return Ok(unquoted); + } else { + eprintln!("bad expand? {}", res.to_sexp()); + todo!(); } } } diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index a4ff430fc..3787b67c7 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -169,7 +169,34 @@ fn test_defmac_basic_test_is_number_neg() { } #[test] -fn test_defmac_create_cond_form() { +fn test_defmac_extension_from_function() { + let prog = indoc! {" + (mod (X) + (defun FX (X) (symbol->string X)) + (defmac F (X) (FX X)) + (c 3 (F X)) + ) + "} + .to_string(); + let res = run_string(&prog, &"(3)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(3 . \"X\")"); +} + +#[test] +fn test_defmac_if_extension() { + let prog = indoc! {" + (mod (X) + (defun FX (X) (if X (number->string 1) 2)) + (defmac F (X) (c 1 (FX X))) + (F X) + ) + "}.to_string(); + let res = run_string(&prog, &"(9)".to_string()).unwrap(); + assert_eq!(res.to_string(), "\"1\""); +} + +#[test] +fn test_defmac_create_match_form() { let prog = indoc! {" ;; Make a simple list match ala ocaml/elm/haskell. ;; @@ -189,50 +216,101 @@ fn test_defmac_create_cond_form() { ) ) - ;; From a list of bindings or constants, build a matcher for the elements. - (defun gather-bindings-list (expr tomatch) - (if (not expr) - () - () + (defun funcall (name args) (c (string->symbol name) args)) + (defun quoted (X) (c 1 X)) + (defun equals (A B) (funcall \"=\" (list A B))) + (defun emit-list-nth (L N) (funcall \"list-nth\" (list L N))) + (defun emit-list-len (L N) (funcall \"list-len\" (list L N))) + (defun emit-if (C T E) (funcall \"if\" (list C T E))) + (defun emit-let (bindings body) (funcall \"let\" (list bindings body))) + + ;; Determine the size of each list as well as the constants and bindings + ;; Return either a list of (number-of-elts matches bindings) or symbol. + (defun build-matches-and-bindings (n pattern matches bindings) + (if (not pattern) + (list n matches bindings) + (if (l pattern) + (if (symbol? (f pattern)) + (build-matches-and-bindings (+ n 1) (r pattern) matches (c (c n (f pattern)) bindings)) + (build-matches-and-bindings (+ n 1) (r pattern) (c (c n (f pattern)) matches) bindings) + ) + pattern + ) + ) ) - ) - (defun gather-bindings (condition expr rest) - (qq - (if (= (list-len (unquote expr)) (unquote (list-len condition))) - (unquote - (let* - ( - (bindings-and-checks (gather-bindings-and-checks condition expr)) - (bindings (f bindings-and-checks)) - (checks (r bindings-and-checks)) - ) - (qq (if checks (let bindings rest))) + ;; Emit code that matches each match list for length and constants. + (defun write-match-code (expr matches) + (if (not matches) + (quoted 1) + (if (l (f matches)) + (let* + ( + (offset (f (f matches))) + (desire (r (f matches))) + (this-match (equals (quoted desire) (emit-list-nth expr (quoted offset)))) + ) + (if (not (r matches)) + (list this-match) + (c this-match (write-match-code expr (r matches))) + ) + ) + (quoted 1) + ) + ) + ) + + ;; Generate let bindings for the bindings indicated in the match. + (defun let-bindings (expr bindings) + (if (not bindings) + () + (let + ((n (f (f bindings))) + (binding (r (f bindings))) + ) + (c (list binding (emit-list-nth expr n)) (let-bindings expr (r bindings))) ) ) - () - ) ) - ) - ;; For each pair, emit an expression that checks for the requested pattern - ;; and returns either the requested result or allows the following matchers - ;; to run. - (defun handle-matches (expr matches) - (if (not matches) - (qq (x (unquote expr))) - (let - ( - (condition (f (f expr))) - (code (f (r (f expr)))) + ;; Generate if expressions that match the indicates matches and return + ;; the indicated code with bindings installed. + (defun match-if (expr clauses) + (if (not clauses) + (list 8) + (let + ((extracted-clause-data (build-matches-and-bindings 0 (f (f clauses)) () ())) + (code (f (r (f clauses)))) + ) + (if (l extracted-clause-data) + (let + ( + (number-of-elts (f extracted-clause-data)) + (matches (list-nth extracted-clause-data 1)) + (bindings (list-nth extracted-clause-data 2)) + ) + (emit-if + (emit-if + (equals (emit-list-len list expr) (quoted number-of-elts)) + ;; then + (list (c (string->symbol \"logand\") (write-match-code expr matches))) + ;; else + () + ) + ;; then + (emit-let (let-bindings expr bindings) code) + ;; else + (match-if expr (r clauses)) + ) + ) + (emit-let (list (list extracted-clause-data expr)) code) + ) + ) ) - (qq (if (unquote (make-match-expr condition expr)) (unquote code) (unquote (handle-matches (r matches))))) - ) ) - ) ;; match as below. - (defmac match (expr . matches) (handle-matches expr matches)) + (defmac match (expr . matches) (match-if expr matches)) (match X ((16 x y) (c 1 (+ x y))) From 4ad9bd2315c647e3fe8f3cc3a2c834c065a3eb8e Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 20 Mar 2023 14:18:01 -0700 Subject: [PATCH 032/196] Working big example --- src/compiler/preprocessor/macros.rs | 138 ++++++++++++++++++++++------ src/tests/compiler/preprocessor.rs | 7 +- 2 files changed, 116 insertions(+), 29 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 8aea3ccfc..827a3b041 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -82,10 +82,6 @@ fn reify_args( let mut allocator = Allocator::new(); let mut converted_args = Vec::new(); for a in args.iter() { - eprintln!("shrink {}", a.to_sexp()); - for (n,e) in env.iter() { - eprintln!("- {} = {}", decode_string(&n), e.to_sexp()); - } let shrunk = evaluator.shrink_bodyform( &mut allocator, prog_args.clone(), @@ -276,7 +272,7 @@ impl ExtensionFunction for StringToSymbol { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { return Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value)))); } else { - eprintln!("pp helper returned {}", decode_string(name)); + eprintln!("pp helper {} returned {} given {}", decode_string(name), body.to_sexp(), args[0].to_sexp()); return Ok(body.clone()); } } @@ -417,25 +413,113 @@ impl ExtensionFunction for List { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - let mut res = SExp::Nil(loc.clone()); - for (n,e) in env.iter() { - eprintln!("- {} = {}", decode_string(&n), e.to_sexp()); - } + let mut allocator = Allocator::new(); + let mut res = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); for a in args.iter().rev() { - eprintln!("list arg {}", a.to_sexp()); - if let Ok(unquoted) = dequote(loc.clone(), a.clone()) { - res = SExp::Cons( - loc.clone(), - unquoted, - Rc::new(res) - ); - } else { - return Ok(body.clone()); - } + res = Rc::new(BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), b"c".to_vec()))), + a.clone(), + res + ] + )); + } + evaluator.shrink_bodyform( + &mut allocator, + prog_args.clone(), + env, + res, + false, + None + ) + } +} + +struct Cons { } + +impl Cons { + fn new() -> Rc { Rc::new(Cons { }) } +} + +impl ExtensionFunction for Cons { + fn required_args(&self) -> Option { Some(2) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + if let (BodyForm::Quoted(a), BodyForm::Quoted(b)) = (args[0].borrow(), args[1].borrow()) { + Ok(Rc::new(BodyForm::Quoted(SExp::Cons(loc.clone(), Rc::new(a.clone()), Rc::new(b.clone()))))) + } else { + Ok(body.clone()) + } + } +} + +struct First { } + +impl First { + fn new() -> Rc { Rc::new(First { }) } +} + +impl ExtensionFunction for First { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + if let BodyForm::Quoted(SExp::Cons(_,a,b)) = args[0].borrow() { + let a_borrowed: &SExp = a.borrow(); + Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) + } else if let BodyForm::Quoted(_) = args[0].borrow() { + Err(CompileErr(loc.clone(), "bad cons in first".to_string())) + } else { + Ok(body.clone()) + } + } +} + +struct Rest { } + +impl Rest { + fn new() -> Rc { Rc::new(Rest { }) } +} + +impl ExtensionFunction for Rest { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + if let BodyForm::Quoted(SExp::Cons(_,a,b)) = args[0].borrow() { + let a_borrowed: &SExp = b.borrow(); + Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) + } else if let BodyForm::Quoted(_) = args[0].borrow() { + Err(CompileErr(loc.clone(), "bad cons in rest".to_string())) + } else { + Ok(body.clone()) } - let list_res = BodyForm::Quoted(res); - eprintln!("list_res {}", list_res.to_sexp()); - Ok(Rc::new(list_res)) } } @@ -472,9 +556,7 @@ impl ExtensionFunction for If { )?; if let Ok(unquoted) = dequote(body.loc(), cond_result) { - eprintln!("unquoted {}", unquoted); if truthy(unquoted) { - eprintln!("truthy, expand {}", args[1].to_sexp()); evaluator.shrink_bodyform( &mut allocator, prog_args.clone(), @@ -484,7 +566,6 @@ impl ExtensionFunction for If { None ) } else { - eprintln!("falsey, expand {}", args[2].to_sexp()); evaluator.shrink_bodyform( &mut allocator, prog_args.clone(), @@ -495,7 +576,6 @@ impl ExtensionFunction for If { ) } } else { - eprintln!("can't reduce if {}", body.to_sexp()); Ok(body.clone()) } } @@ -535,6 +615,9 @@ impl PreprocessorExtension { let extfuns = [ (b"if".to_vec(), If::new()), (b"list".to_vec(), List::new()), + (b"c".to_vec(), Cons::new()), + (b"f".to_vec(), First::new()), + (b"r".to_vec(), Rest::new()), (b"string?".to_vec(), StringQ::new()), (b"number?".to_vec(), NumberQ::new()), @@ -571,6 +654,9 @@ impl EvalExtension for PreprocessorExtension { } eprintln!("try function {}", body.to_sexp()); + for (n,v) in env.iter() { + eprintln!("- {} = {}", decode_string(&n), v.to_sexp()); + } let args = if extfun.want_interp() { reify_args( diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 3787b67c7..6abfa29c8 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -201,7 +201,8 @@ fn test_defmac_create_match_form() { ;; Make a simple list match ala ocaml/elm/haskell. ;; ;; The real version will be more elaborate. This is a test case and a demo. - (mod (X) + (mod X + (include *standard-cl-21*) (defun list-nth (L N) (if N (list-nth (r L) (- N 1)) @@ -291,9 +292,9 @@ fn test_defmac_create_match_form() { ) (emit-if (emit-if - (equals (emit-list-len list expr) (quoted number-of-elts)) + (equals (emit-list-len expr 0) (quoted number-of-elts)) ;; then - (list (c (string->symbol \"logand\") (write-match-code expr matches))) + (c (string->symbol \"logand\") (write-match-code expr matches)) ;; else () ) From 5e15b2b6feeefc3366513706ca950baad0e1b865 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 21 Mar 2023 09:29:17 -0700 Subject: [PATCH 033/196] Adding tests of added things --- src/tests/compiler/preprocessor.rs | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 6abfa29c8..5ece97456 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -325,3 +325,75 @@ fn test_defmac_create_match_form() { let res = run_string(&prog, &"(3 () 1001 1002)".to_string()).unwrap(); assert_eq!(res.to_string(), "1002"); } + +#[test] +fn test_defmac_stringq() { + let prog = indoc! {" + (mod () + (defmac is-string (X) (string? X)) + (list (is-string X) (is-string \"X\") (is-string 3)) + ) + "}.to_string(); + let res = run_string(&prog, &"()".to_string()).unwrap(); + assert_eq!(res.to_string(), "(() 1 ())"); +} + +#[test] +fn test_defmac_numberq() { + let prog = indoc! {" + (mod () + (defmac is-number (X) (number? X)) + (list (is-number X) (is-number \"X\") (is-number 3)) + ) + "}.to_string(); + let res = run_string(&prog, &"()".to_string()).unwrap(); + assert_eq!(res.to_string(), "(() () 1)"); +} + +#[test] +fn test_defmac_symbolq() { + let prog = indoc! {" + (mod () + (defmac is-symbol (X) (symbol? X)) + (list (is-symbol X) (is-symbol \"X\") (is-symbol 3)) + ) + "}.to_string(); + let res = run_string(&prog, &"()".to_string()).unwrap(); + assert_eq!(res.to_string(), "(1 () ())"); +} + +#[test] +fn test_defmac_string_to_symbol() { + let prog = indoc! {" + (mod () + (defmac is-symbol (X) (symbol? X)) + (list (is-symbol X) (is-symbol \"X\") (is-symbol 3)) + ) + "}.to_string(); + let res = run_string(&prog, &"()".to_string()).unwrap(); + assert_eq!(res.to_string(), "(1 () ())"); +} + +#[test] +fn test_defmac_string_to_symbol_converts() { + let prog = indoc! {" + (mod (X) + (defmac let_pi (code) (qq (let (((unquote (string->symbol \"pi\")) 31415)) (unquote code)))) + (let_pi (+ pi X)) + ) + "}.to_string(); + let res = run_string(&prog, &"(5)".to_string()).unwrap(); + assert_eq!(res.to_string(), "31420"); +} + +#[test] +fn test_defmac_string_needs_conversion() { + let prog = indoc! {" + (mod (X) + (defmac let_pi (code) (qq (let ((\"pi\" 31415)) (unquote code)))) + (let_pi (+ pi X)) + ) + "}.to_string(); + let res = run_string(&prog, &"(5)".to_string()); + assert!(res.is_err()); +} From 3a1431c4f54fb34731351d62d812a526d321011d Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 21 Mar 2023 10:19:12 -0700 Subject: [PATCH 034/196] Finish substring, more tests --- src/compiler/preprocessor/macros.rs | 60 ++++++++++++++++++++++++----- src/tests/compiler/preprocessor.rs | 16 ++++++++ 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 827a3b041..b0b45ab36 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -3,8 +3,9 @@ use std::collections::HashMap; use std::rc::Rc; use clvmr::allocator::Allocator; +use num_traits::ToPrimitive; -use crate::classic::clvm::__type_compatibility__::bi_one; +use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::compiler::clvm::truthy; use crate::compiler::comptypes::{BodyForm, CompileErr}; @@ -61,14 +62,37 @@ enum MatchedNumber { } fn match_number(body: Rc) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Integer(il,n)) = body.borrow() { - Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))) - } else if let BodyForm::Quoted(SExp::QuotedString(ql,b'x',b)) = body.borrow() { - Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))) - } else if let BodyForm::Quoted(_) = body.borrow() { - Err(CompileErr(body.loc(), "number required".to_string())) + match body.borrow() { + BodyForm::Quoted(SExp::Integer(il,n)) => { + Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))) + } + BodyForm::Quoted(SExp::QuotedString(ql,b'x',b)) => { + Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))) + } + BodyForm::Quoted(SExp::Nil(il)) => { + Ok(Some(MatchedNumber::MatchedInt(il.clone(), bi_zero()))) + } + BodyForm::Quoted(_) => { + Err(CompileErr(body.loc(), "number required".to_string())) + } + _ => Ok(None) + } +} + +fn numeric_value(body: Rc) -> Result { + match match_number(body.clone())? { + Some(MatchedNumber::MatchedInt(_, n)) => Ok(n.clone()), + Some(MatchedNumber::MatchedHex(_, h)) => Ok(number_from_u8(&h)), + _ => Err(CompileErr(body.loc(), "Not a number".to_string())) + } +} + +fn usize_value(body: Rc) -> Result { + let n = numeric_value(body.clone())?; + if let Some(res) = n.to_usize() { + Ok(res) } else { - Ok(None) + Err(CompileErr(body.loc(), "Value out of range".to_string())) } } @@ -390,7 +414,25 @@ impl ExtensionFunction for Substring { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - todo!(); + let start_element = usize_value(args[1].clone())?; + let end_element = usize_value(args[2].clone())?; + + match args[0].borrow() { + BodyForm::Quoted(SExp::QuotedString(l,ch,s)) => { + if start_element > end_element || start_element > s.len() || end_element > s.len() { + return Err(CompileErr(l.clone(), "start greater than end in substring".to_string())); + } + let result_value: Vec = + s.iter().take(end_element).skip(start_element).copied().collect(); + Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(l.clone(), *ch, result_value)))) + } + BodyForm::Quoted(_) => { + Err(CompileErr(body.loc(), "Not a string".to_string())) + } + _ => { + Ok(body.clone()) + } + } } } diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 5ece97456..286ace546 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -397,3 +397,19 @@ fn test_defmac_string_needs_conversion() { let res = run_string(&prog, &"(5)".to_string()); assert!(res.is_err()); } + +#[test] +fn test_defmac_string_substr_0() { + let prog = indoc! {" + (mod (X) + (defmac first-letter-of (Q) + (let ((first-character (substring (symbol->string Q) 0 1))) + (qq (c (unquote first-character) (unquote (string->symbol first-character)))) + ) + ) + (first-letter-of Xanadu) + ) + "}.to_string(); + let res = run_string(&prog, &"(5999)".to_string()).unwrap(); + assert_eq!(res.to_string(), "(\"X\" . 5999)"); +} From 514ca1bcf56c3c14f3bada0614c3412eb488aaa7 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 21 Mar 2023 12:27:10 -0700 Subject: [PATCH 035/196] More --- src/compiler/preprocessor/macros.rs | 35 +++++++++++++++++++++++++++++ src/tests/compiler/preprocessor.rs | 19 ++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index b0b45ab36..2d94b4553 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::rc::Rc; use clvmr::allocator::Allocator; +use num_bigint::ToBigInt; use num_traits::ToPrimitive; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; @@ -395,6 +396,39 @@ impl ExtensionFunction for StringToNumber { } } +struct StringLength { } + +impl StringLength { + fn new() -> Rc { Rc::new(StringLength { }) } +} + +impl ExtensionFunction for StringLength { + fn required_args(&self) -> Option { Some(1) } + + fn try_eval( + &self, + evaluator: &Evaluator, + prog_args: Rc, + env: &HashMap, Rc>, + loc: &Srcloc, + name: &[u8], + args: &[Rc], + body: Rc, + ) -> Result, CompileErr> { + if let Some((loc, mut value)) = match_quoted_string(args[0].clone())? { + if let Some(len_bi) = value.len().to_bigint() { + Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc.clone(), len_bi)))) + } else { + Err(CompileErr(loc.clone(), "Error getting string length".to_string())) + } + } else { + eprintln!("pp helper returned {}", decode_string(name)); + Ok(body.clone()) + } + } +} + + struct Substring { } impl Substring { @@ -671,6 +705,7 @@ impl PreprocessorExtension { (b"number->string".to_vec(), NumberToString::new()), (b"string-append".to_vec(), StringAppend::new()), + (b"string-length".to_vec(), StringLength::new()), (b"substring".to_vec(), Substring::new()), ]; PreprocessorExtension { extfuns: HashMap::from(extfuns) } diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 286ace546..ad48f9898 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -413,3 +413,22 @@ fn test_defmac_string_substr_0() { let res = run_string(&prog, &"(5999)".to_string()).unwrap(); assert_eq!(res.to_string(), "(\"X\" . 5999)"); } + +#[test] +fn test_defmac_string_substr_1() { + let prog = indoc! {" + (mod (test_variable_name) + (defmac bind-tail-of-symbol (N Q CODE) + (let* + ((stringified (symbol->string Q)) + (slen (string-length stringified)) + (suffix (string->symbol (substring stringified N slen)))) + (qq (let (((unquote suffix) (r (unquote Q)))) (unquote CODE))) + ) + ) + (bind-tail-of-symbol 5 test_variable_name (c 9999 variable_name)) + ) + "}.to_string(); + let res = run_string(&prog, &"((87 89 91))".to_string()).unwrap(); + assert_eq!(res.to_string(), "(9999 89 91)"); +} From 51bce1b625d6dbdb7793d1ecd25d61d6588452c6 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 21 Mar 2023 15:09:13 -0700 Subject: [PATCH 036/196] more --- src/compiler/preprocessor/macros.rs | 10 ++++- src/tests/compiler/preprocessor.rs | 67 +++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 2d94b4553..ac1c68add 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -392,7 +392,15 @@ impl ExtensionFunction for StringToNumber { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - todo!(); + if let Some((loc, mut value)) = match_quoted_string(args[0].clone())? { + if let Ok(cvt_bi) = decode_string(&value).parse::() { + Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc.clone(), cvt_bi)))) + } else { + Err(CompileErr(loc.clone(), "bad number".to_string())) + } + } else { + Err(CompileErr(loc.clone(), "should be given a string".to_string())) + } } } diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index ad48f9898..40495c8df 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -415,7 +415,7 @@ fn test_defmac_string_substr_0() { } #[test] -fn test_defmac_string_substr_1() { +fn test_defmac_string_substr_bad() { let prog = indoc! {" (mod (test_variable_name) (defmac bind-tail-of-symbol (N Q CODE) @@ -426,9 +426,68 @@ fn test_defmac_string_substr_1() { (qq (let (((unquote suffix) (r (unquote Q)))) (unquote CODE))) ) ) - (bind-tail-of-symbol 5 test_variable_name (c 9999 variable_name)) + (bind-tail-of-symbol 100 test_variable_name (c 9999 variable_name)) ) "}.to_string(); - let res = run_string(&prog, &"((87 89 91))".to_string()).unwrap(); - assert_eq!(res.to_string(), "(9999 89 91)"); + let res = run_string(&prog, &"((87 89 91))".to_string()); + assert!(res.is_err()); +} + +#[test] +fn test_defmac_string_to_number_0() { + let prog = indoc! {" + (mod (X_7) + (defmac add-n-to (X) + (let + ((stringified (symbol->string X)) + (slen (string-length stringified)) + (number-part (substring stringified (- slen 1) slen)) + (numeric-value (string->number number-part))) + (qq (+ (unquote numeric-value) (unquote X))) + ) + ) + (add-n-to X_7) + ) + "}.to_string(); + let res = run_string(&prog, &"(31)".to_string()).unwrap(); + assert_eq!(res.to_string(), "38"); +} + +#[test] +fn test_defmac_string_to_number_bad() { + let prog = indoc! {" + (mod (X_A) + (defmac add-n-to (X) + (let + ((stringified (symbol->string X)) + (slen (string-length stringified)) + (number-part (substring stringified (- slen 1) slen)) + (numeric-value (string->number number-part))) + (qq (+ (unquote numeric-value) (unquote X))) + ) + ) + (add-n-to X_A) + ) + "}.to_string(); + let res = run_string(&prog, &"(31)".to_string()); + assert!(res.is_err()); +} + +#[test] +fn test_defmac_number_to_string() { + let prog = indoc! {" + (mod (Q) + (defmac with-my-length (X) + (let* + ((stringified (symbol->string X)) + (slen (string-length stringified))) + (string->symbol (string-append stringified \"-\" (number->string slen))) + ) + ) + (defun F (Xanadu-6) (+ (with-my-length Xanadu) 99)) + (F Q) + ) + "}.to_string(); + let res = run_string(&prog, &"(37)".to_string()).unwrap(); + assert_eq!(res.to_string(), "136"); } From dfcc9c664c04001ee4043ac6ce6c52f3f0e0bd42 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 21 Mar 2023 15:56:54 -0700 Subject: [PATCH 037/196] clippy --- src/compiler/preprocessor/macros.rs | 154 ++++++++++++++-------------- src/compiler/preprocessor/mod.rs | 8 +- 2 files changed, 83 insertions(+), 79 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index ac1c68add..76d622424 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -20,13 +20,13 @@ use crate::util::{Number, number_from_u8}; fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { let is_string = match body.borrow() { - BodyForm::Quoted(SExp::QuotedString(al,b'x',an)) => { + BodyForm::Quoted(SExp::QuotedString(_,b'x',_)) => { None } BodyForm::Quoted(SExp::QuotedString(al,_,an)) => { Some((al.clone(), an.clone())) } - BodyForm::Value(SExp::QuotedString(al,b'x',an)) => { + BodyForm::Value(SExp::QuotedString(_,b'x',_)) => { None } BodyForm::Value(SExp::QuotedString(al,_,an)) => { @@ -101,7 +101,6 @@ fn reify_args( evaluator: &Evaluator, prog_args: Rc, env: &HashMap, Rc>, - loc: &Srcloc, args: &[Rc] ) -> Result>, CompileErr> { let mut allocator = Allocator::new(); @@ -151,11 +150,11 @@ impl ExtensionFunction for StringQ { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -187,11 +186,11 @@ impl ExtensionFunction for NumberQ { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -223,11 +222,11 @@ impl ExtensionFunction for SymbolQ { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -259,11 +258,11 @@ impl ExtensionFunction for SymbolToString { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, + _loc: &Srcloc, + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -286,18 +285,17 @@ impl ExtensionFunction for StringToSymbol { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, + _loc: &Srcloc, + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { return Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value)))); } else { - eprintln!("pp helper {} returned {} given {}", decode_string(name), body.to_sexp(), args[0].to_sexp()); return Ok(body.clone()); } } @@ -314,11 +312,11 @@ impl ExtensionFunction for StringAppend { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, + _loc: &Srcloc, + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -331,7 +329,6 @@ impl ExtensionFunction for StringAppend { } out_vec.append(&mut value); } else { - eprintln!("pp helper returned {}", decode_string(name)); return Ok(body.clone()); } } @@ -350,11 +347,11 @@ impl ExtensionFunction for NumberToString { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, + _loc: &Srcloc, + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -384,15 +381,15 @@ impl ExtensionFunction for StringToNumber { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], + _name: &[u8], args: &[Rc], - body: Rc, + _body: Rc, ) -> Result, CompileErr> { - if let Some((loc, mut value)) = match_quoted_string(args[0].clone())? { + if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Ok(cvt_bi) = decode_string(&value).parse::() { Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc.clone(), cvt_bi)))) } else { @@ -415,22 +412,21 @@ impl ExtensionFunction for StringLength { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, + _loc: &Srcloc, + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { - if let Some((loc, mut value)) = match_quoted_string(args[0].clone())? { + if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Some(len_bi) = value.len().to_bigint() { Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc.clone(), len_bi)))) } else { Err(CompileErr(loc.clone(), "Error getting string length".to_string())) } } else { - eprintln!("pp helper returned {}", decode_string(name)); Ok(body.clone()) } } @@ -448,11 +444,11 @@ impl ExtensionFunction for Substring { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, + _loc: &Srcloc, + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -493,9 +489,9 @@ impl ExtensionFunction for List { prog_args: Rc, env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], + _name: &[u8], args: &[Rc], - body: Rc, + _body: Rc, ) -> Result, CompileErr> { let mut allocator = Allocator::new(); let mut res = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); @@ -531,11 +527,11 @@ impl ExtensionFunction for Cons { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -558,15 +554,15 @@ impl ExtensionFunction for First { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Cons(_,a,b)) = args[0].borrow() { + if let BodyForm::Quoted(SExp::Cons(_,a,_)) = args[0].borrow() { let a_borrowed: &SExp = a.borrow(); Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) } else if let BodyForm::Quoted(_) = args[0].borrow() { @@ -588,15 +584,15 @@ impl ExtensionFunction for Rest { fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, + _evaluator: &Evaluator, + _prog_args: Rc, + _env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Cons(_,a,b)) = args[0].borrow() { + if let BodyForm::Quoted(SExp::Cons(_,_,b)) = args[0].borrow() { let a_borrowed: &SExp = b.borrow(); Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) } else if let BodyForm::Quoted(_) = args[0].borrow() { @@ -623,8 +619,8 @@ impl ExtensionFunction for If { evaluator: &Evaluator, prog_args: Rc, env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], + _loc: &Srcloc, + _name: &[u8], args: &[Rc], body: Rc, ) -> Result, CompileErr> { @@ -672,9 +668,16 @@ impl ExtensionFunction for If { /// /// These functions are provided: /// +/// Enhanced versions of builtin macros: +/// +/// if -- first class short circuiting, no round trip to CLVM space +/// list -- simple own implementation +/// c -- cons preserving exact input values +/// f -- first and rest exactly preserving part of cons. +/// r -- +/// /// Queries /// -/// pair? /// string? /// number? /// symbol? @@ -689,7 +692,9 @@ impl ExtensionFunction for If { /// Working with values /// /// string-append s0 s1 ... +/// string-length /// substring s start end +/// pub struct PreprocessorExtension { extfuns: HashMap, Rc> } @@ -748,7 +753,6 @@ impl EvalExtension for PreprocessorExtension { evaluator, prog_args.clone(), env, - loc, raw_args )? } else { diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index a24c31d95..2ddb1358d 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -10,12 +10,12 @@ use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::compiler::compiler::KNOWN_DIALECTS; use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc}; -use crate::compiler::evaluate::{ArgInputs, create_argument_captures, dequote, EvalExtension, Evaluator}; +use crate::compiler::evaluate::{ArgInputs, create_argument_captures, dequote, Evaluator}; use crate::compiler::frontend::compile_helperform; -use crate::compiler::sexp::{Atom, decode_string, enlist, First, NodeSel, parse_sexp, SelectNode, SExp, ThisNode}; +use crate::compiler::sexp::{Atom, decode_string, enlist, NodeSel, parse_sexp, SelectNode, SExp, ThisNode}; use crate::compiler::preprocessor::macros::PreprocessorExtension; use crate::compiler::srcloc::Srcloc; -use crate::util::{ErrInto, Number, number_from_u8}; +use crate::util::ErrInto; struct Preprocessor { opts: Rc, @@ -101,7 +101,7 @@ impl Preprocessor { let first_expanded = self.expand_macros(f.clone())?; let rest_expanded = self.expand_macros(r.clone())?; let new_self = Rc::new(SExp::Cons(l.clone(), first_expanded, rest_expanded)); - if let Ok(NodeSel::Cons((nl, name), args)) = NodeSel::Cons( + if let Ok(NodeSel::Cons((_, name), args)) = NodeSel::Cons( Atom::Here(()), ThisNode::Here ).select_nodes(new_self.clone()) { // See if it's a form that calls one of our macros. From 4b1b14bff10105b9da1fb8c9cbe847a06f36460e Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 22 Mar 2023 09:12:49 -0700 Subject: [PATCH 038/196] fmt --- src/compiler/comptypes.rs | 1 - src/compiler/evaluate.rs | 4 +- src/compiler/preprocessor/macros.rs | 443 +++++++++++++++------------- src/compiler/preprocessor/mod.rs | 80 ++--- src/compiler/sexp.rs | 9 +- src/tests/compiler/preprocessor.rs | 36 ++- 6 files changed, 316 insertions(+), 257 deletions(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index a36ba2c76..c23454172 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -755,4 +755,3 @@ pub fn join_vecs_to_string(sep: Vec, vecs: &[Vec]) -> String { decode_string(&s) } - diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index a7e2b1f55..f5fcf4ef4 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -628,7 +628,7 @@ impl<'info> Evaluator { helpers, mash_conditions: false, ignore_exn: false, - extensions: Vec::new() + extensions: Vec::new(), } } @@ -944,7 +944,7 @@ impl<'info> Evaluator { &l, call_name, &arguments_to_convert, - body.clone() + body.clone(), )? { return Ok(res); } diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 76d622424..f04f0db36 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -12,33 +12,22 @@ use crate::compiler::clvm::truthy; use crate::compiler::comptypes::{BodyForm, CompileErr}; use crate::compiler::evaluate::{EvalExtension, Evaluator}; use crate::compiler::preprocessor::dequote; -use crate::compiler::sexp::{SExp, decode_string}; -use crate::compiler::srcloc::{Srcloc}; -use crate::util::{Number, number_from_u8}; +use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::srcloc::Srcloc; +use crate::util::{number_from_u8, Number}; // If the bodyform represents a constant, only match a quoted string. fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { - let is_string = - match body.borrow() { - BodyForm::Quoted(SExp::QuotedString(_,b'x',_)) => { - None - } - BodyForm::Quoted(SExp::QuotedString(al,_,an)) => { - Some((al.clone(), an.clone())) - } - BodyForm::Value(SExp::QuotedString(_,b'x',_)) => { - None - } - BodyForm::Value(SExp::QuotedString(al,_,an)) => { - Some((al.clone(), an.clone())) - } - BodyForm::Quoted(_) => { - None - } - _ => { - return Ok(None); - } - }; + let is_string = match body.borrow() { + BodyForm::Quoted(SExp::QuotedString(_, b'x', _)) => None, + BodyForm::Quoted(SExp::QuotedString(al, _, an)) => Some((al.clone(), an.clone())), + BodyForm::Value(SExp::QuotedString(_, b'x', _)) => None, + BodyForm::Value(SExp::QuotedString(al, _, an)) => Some((al.clone(), an.clone())), + BodyForm::Quoted(_) => None, + _ => { + return Ok(None); + } + }; if let Some((loc, s)) = is_string { Ok(Some((loc, s))) @@ -48,8 +37,8 @@ fn match_quoted_string(body: Rc) -> Result)>, } fn match_atom(body: Rc) -> Result)>, CompileErr> { - if let BodyForm::Quoted(SExp::Atom(al,an)) = body.borrow() { - Ok(Some((al.clone(),an.clone()))) + if let BodyForm::Quoted(SExp::Atom(al, an)) = body.borrow() { + Ok(Some((al.clone(), an.clone()))) } else if let BodyForm::Quoted(_) = body.borrow() { Err(CompileErr(body.loc(), "atom required".to_string())) } else { @@ -59,24 +48,22 @@ fn match_atom(body: Rc) -> Result)>, CompileEr enum MatchedNumber { MatchedInt(Srcloc, Number), - MatchedHex(Srcloc, Vec) + MatchedHex(Srcloc, Vec), } fn match_number(body: Rc) -> Result, CompileErr> { match body.borrow() { - BodyForm::Quoted(SExp::Integer(il,n)) => { + BodyForm::Quoted(SExp::Integer(il, n)) => { Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))) } - BodyForm::Quoted(SExp::QuotedString(ql,b'x',b)) => { + BodyForm::Quoted(SExp::QuotedString(ql, b'x', b)) => { Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))) } BodyForm::Quoted(SExp::Nil(il)) => { Ok(Some(MatchedNumber::MatchedInt(il.clone(), bi_zero()))) } - BodyForm::Quoted(_) => { - Err(CompileErr(body.loc(), "number required".to_string())) - } - _ => Ok(None) + BodyForm::Quoted(_) => Err(CompileErr(body.loc(), "number required".to_string())), + _ => Ok(None), } } @@ -84,7 +71,7 @@ fn numeric_value(body: Rc) -> Result { match match_number(body.clone())? { Some(MatchedNumber::MatchedInt(_, n)) => Ok(n.clone()), Some(MatchedNumber::MatchedHex(_, h)) => Ok(number_from_u8(&h)), - _ => Err(CompileErr(body.loc(), "Not a number".to_string())) + _ => Err(CompileErr(body.loc(), "Not a number".to_string())), } } @@ -101,7 +88,7 @@ fn reify_args( evaluator: &Evaluator, prog_args: Rc, env: &HashMap, Rc>, - args: &[Rc] + args: &[Rc], ) -> Result>, CompileErr> { let mut allocator = Allocator::new(); let mut converted_args = Vec::new(); @@ -112,7 +99,7 @@ fn reify_args( env, a.clone(), false, - None + None, )?; converted_args.push(shrunk); } @@ -125,7 +112,9 @@ fn reify_args( /// needed. These are held in a collection and looked up. To be maximally /// conservative with typing and lifetime, we hold these via Rc. pub trait ExtensionFunction { - fn want_interp(&self) -> bool { true } + fn want_interp(&self) -> bool { + true + } fn required_args(&self) -> Option; fn try_eval( &self, @@ -139,14 +128,18 @@ pub trait ExtensionFunction { ) -> Result, CompileErr>; } -struct StringQ { } +struct StringQ {} impl StringQ { - fn new() -> Rc { Rc::new(StringQ { }) } + fn new() -> Rc { + Rc::new(StringQ {}) + } } impl ExtensionFunction for StringQ { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -158,31 +151,30 @@ impl ExtensionFunction for StringQ { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - let res = - match match_quoted_string(args[0].clone()) { - Ok(Some(_)) => { - SExp::Integer(loc.clone(), bi_one()) - } - Ok(None) => { - return Ok(body.clone()); - } - Err(_) => { - SExp::Nil(loc.clone()) - } - }; + let res = match match_quoted_string(args[0].clone()) { + Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), + Ok(None) => { + return Ok(body.clone()); + } + Err(_) => SExp::Nil(loc.clone()), + }; Ok(Rc::new(BodyForm::Quoted(res))) } } -struct NumberQ { } +struct NumberQ {} impl NumberQ { - fn new() -> Rc { Rc::new(NumberQ { }) } + fn new() -> Rc { + Rc::new(NumberQ {}) + } } impl ExtensionFunction for NumberQ { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -194,31 +186,30 @@ impl ExtensionFunction for NumberQ { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - let res = - match match_number(args[0].clone()) { - Ok(Some(_)) => { - SExp::Integer(loc.clone(), bi_one()) - } - Ok(None) => { - return Ok(body.clone()); - } - Err(_) => { - SExp::Nil(loc.clone()) - } - }; + let res = match match_number(args[0].clone()) { + Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), + Ok(None) => { + return Ok(body.clone()); + } + Err(_) => SExp::Nil(loc.clone()), + }; Ok(Rc::new(BodyForm::Quoted(res))) } } -struct SymbolQ { } +struct SymbolQ {} impl SymbolQ { - fn new() -> Rc { Rc::new(SymbolQ { }) } + fn new() -> Rc { + Rc::new(SymbolQ {}) + } } impl ExtensionFunction for SymbolQ { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -230,31 +221,30 @@ impl ExtensionFunction for SymbolQ { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - let res = - match match_atom(args[0].clone()) { - Ok(Some(_)) => { - SExp::Integer(loc.clone(), bi_one()) - } - Ok(None) => { - return Ok(body.clone()); - } - Err(_) => { - SExp::Nil(loc.clone()) - } - }; + let res = match match_atom(args[0].clone()) { + Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), + Ok(None) => { + return Ok(body.clone()); + } + Err(_) => SExp::Nil(loc.clone()), + }; Ok(Rc::new(BodyForm::Quoted(res))) } } -struct SymbolToString { } +struct SymbolToString {} impl SymbolToString { - fn new() -> Rc { Rc::new(SymbolToString { }) } + fn new() -> Rc { + Rc::new(SymbolToString {}) + } } impl ExtensionFunction for SymbolToString { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -267,21 +257,27 @@ impl ExtensionFunction for SymbolToString { body: Rc, ) -> Result, CompileErr> { if let Some((loc, value)) = match_atom(args[0].clone())? { - return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(loc,b'\"',value)))); + return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + loc, b'\"', value, + )))); } else { return Ok(body.clone()); } } } -struct StringToSymbol { } +struct StringToSymbol {} impl StringToSymbol { - fn new() -> Rc { Rc::new(StringToSymbol { }) } + fn new() -> Rc { + Rc::new(StringToSymbol {}) + } } impl ExtensionFunction for StringToSymbol { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -294,21 +290,25 @@ impl ExtensionFunction for StringToSymbol { body: Rc, ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - return Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc,value)))); + return Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc, value)))); } else { return Ok(body.clone()); } } } -struct StringAppend { } +struct StringAppend {} impl StringAppend { - fn new() -> Rc { Rc::new(StringAppend { }) } + fn new() -> Rc { + Rc::new(StringAppend {}) + } } impl ExtensionFunction for StringAppend { - fn required_args(&self) -> Option { None } + fn required_args(&self) -> Option { + None + } fn try_eval( &self, @@ -332,18 +332,26 @@ impl ExtensionFunction for StringAppend { return Ok(body.clone()); } } - return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(out_loc.unwrap_or_else(|| body.loc()),b'\"',out_vec)))); + return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + out_loc.unwrap_or_else(|| body.loc()), + b'\"', + out_vec, + )))); } } -struct NumberToString { } +struct NumberToString {} impl NumberToString { - fn new() -> Rc { Rc::new(NumberToString { }) } + fn new() -> Rc { + Rc::new(NumberToString {}) + } } impl ExtensionFunction for NumberToString { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -356,28 +364,33 @@ impl ExtensionFunction for NumberToString { body: Rc, ) -> Result, CompileErr> { let match_res = match_number(args[0].clone())?; - let (use_loc, int_val) = - match &match_res { - Some(MatchedNumber::MatchedInt(l,i)) => { (l.clone(), i.clone()) } - Some(MatchedNumber::MatchedHex(l,h)) => { - (l.clone(), number_from_u8(&h)) - } - _ => { - return Ok(body.clone()); - } - }; - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(use_loc, b'\"', int_val.to_string().as_bytes().to_vec())))) + let (use_loc, int_val) = match &match_res { + Some(MatchedNumber::MatchedInt(l, i)) => (l.clone(), i.clone()), + Some(MatchedNumber::MatchedHex(l, h)) => (l.clone(), number_from_u8(&h)), + _ => { + return Ok(body.clone()); + } + }; + Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + use_loc, + b'\"', + int_val.to_string().as_bytes().to_vec(), + )))) } } -struct StringToNumber { } +struct StringToNumber {} impl StringToNumber { - fn new() -> Rc { Rc::new(StringToNumber { }) } + fn new() -> Rc { + Rc::new(StringToNumber {}) + } } impl ExtensionFunction for StringToNumber { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -391,24 +404,34 @@ impl ExtensionFunction for StringToNumber { ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Ok(cvt_bi) = decode_string(&value).parse::() { - Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc.clone(), cvt_bi)))) + Ok(Rc::new(BodyForm::Quoted(SExp::Integer( + loc.clone(), + cvt_bi, + )))) } else { Err(CompileErr(loc.clone(), "bad number".to_string())) } } else { - Err(CompileErr(loc.clone(), "should be given a string".to_string())) + Err(CompileErr( + loc.clone(), + "should be given a string".to_string(), + )) } } } -struct StringLength { } +struct StringLength {} impl StringLength { - fn new() -> Rc { Rc::new(StringLength { }) } + fn new() -> Rc { + Rc::new(StringLength {}) + } } impl ExtensionFunction for StringLength { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -422,9 +445,15 @@ impl ExtensionFunction for StringLength { ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Some(len_bi) = value.len().to_bigint() { - Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc.clone(), len_bi)))) + Ok(Rc::new(BodyForm::Quoted(SExp::Integer( + loc.clone(), + len_bi, + )))) } else { - Err(CompileErr(loc.clone(), "Error getting string length".to_string())) + Err(CompileErr( + loc.clone(), + "Error getting string length".to_string(), + )) } } else { Ok(body.clone()) @@ -432,15 +461,18 @@ impl ExtensionFunction for StringLength { } } - -struct Substring { } +struct Substring {} impl Substring { - fn new() -> Rc { Rc::new(Substring { }) } + fn new() -> Rc { + Rc::new(Substring {}) + } } impl ExtensionFunction for Substring { - fn required_args(&self) -> Option { Some(3) } + fn required_args(&self) -> Option { + Some(3) + } fn try_eval( &self, @@ -456,32 +488,43 @@ impl ExtensionFunction for Substring { let end_element = usize_value(args[2].clone())?; match args[0].borrow() { - BodyForm::Quoted(SExp::QuotedString(l,ch,s)) => { + BodyForm::Quoted(SExp::QuotedString(l, ch, s)) => { if start_element > end_element || start_element > s.len() || end_element > s.len() { - return Err(CompileErr(l.clone(), "start greater than end in substring".to_string())); + return Err(CompileErr( + l.clone(), + "start greater than end in substring".to_string(), + )); } - let result_value: Vec = - s.iter().take(end_element).skip(start_element).copied().collect(); - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString(l.clone(), *ch, result_value)))) - } - BodyForm::Quoted(_) => { - Err(CompileErr(body.loc(), "Not a string".to_string())) - } - _ => { - Ok(body.clone()) + let result_value: Vec = s + .iter() + .take(end_element) + .skip(start_element) + .copied() + .collect(); + Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + l.clone(), + *ch, + result_value, + )))) } + BodyForm::Quoted(_) => Err(CompileErr(body.loc(), "Not a string".to_string())), + _ => Ok(body.clone()), } } } -struct List { } +struct List {} impl List { - fn new() -> Rc { Rc::new(List { }) } + fn new() -> Rc { + Rc::new(List {}) + } } impl ExtensionFunction for List { - fn required_args(&self) -> Option { None } + fn required_args(&self) -> Option { + None + } fn try_eval( &self, @@ -501,29 +544,26 @@ impl ExtensionFunction for List { vec![ Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), b"c".to_vec()))), a.clone(), - res - ] + res, + ], )); } - evaluator.shrink_bodyform( - &mut allocator, - prog_args.clone(), - env, - res, - false, - None - ) + evaluator.shrink_bodyform(&mut allocator, prog_args.clone(), env, res, false, None) } } -struct Cons { } +struct Cons {} impl Cons { - fn new() -> Rc { Rc::new(Cons { }) } + fn new() -> Rc { + Rc::new(Cons {}) + } } impl ExtensionFunction for Cons { - fn required_args(&self) -> Option { Some(2) } + fn required_args(&self) -> Option { + Some(2) + } fn try_eval( &self, @@ -536,21 +576,29 @@ impl ExtensionFunction for Cons { body: Rc, ) -> Result, CompileErr> { if let (BodyForm::Quoted(a), BodyForm::Quoted(b)) = (args[0].borrow(), args[1].borrow()) { - Ok(Rc::new(BodyForm::Quoted(SExp::Cons(loc.clone(), Rc::new(a.clone()), Rc::new(b.clone()))))) + Ok(Rc::new(BodyForm::Quoted(SExp::Cons( + loc.clone(), + Rc::new(a.clone()), + Rc::new(b.clone()), + )))) } else { Ok(body.clone()) } } } -struct First { } +struct First {} impl First { - fn new() -> Rc { Rc::new(First { }) } + fn new() -> Rc { + Rc::new(First {}) + } } impl ExtensionFunction for First { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -562,7 +610,7 @@ impl ExtensionFunction for First { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Cons(_,a,_)) = args[0].borrow() { + if let BodyForm::Quoted(SExp::Cons(_, a, _)) = args[0].borrow() { let a_borrowed: &SExp = a.borrow(); Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) } else if let BodyForm::Quoted(_) = args[0].borrow() { @@ -573,14 +621,18 @@ impl ExtensionFunction for First { } } -struct Rest { } +struct Rest {} impl Rest { - fn new() -> Rc { Rc::new(Rest { }) } + fn new() -> Rc { + Rc::new(Rest {}) + } } impl ExtensionFunction for Rest { - fn required_args(&self) -> Option { Some(1) } + fn required_args(&self) -> Option { + Some(1) + } fn try_eval( &self, @@ -592,7 +644,7 @@ impl ExtensionFunction for Rest { args: &[Rc], body: Rc, ) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Cons(_,_,b)) = args[0].borrow() { + if let BodyForm::Quoted(SExp::Cons(_, _, b)) = args[0].borrow() { let a_borrowed: &SExp = b.borrow(); Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) } else if let BodyForm::Quoted(_) = args[0].borrow() { @@ -603,16 +655,22 @@ impl ExtensionFunction for Rest { } } -struct If { } +struct If {} impl If { - fn new() -> Rc { Rc::new(If { }) } + fn new() -> Rc { + Rc::new(If {}) + } } impl ExtensionFunction for If { - fn want_interp(&self) -> bool { false } + fn want_interp(&self) -> bool { + false + } - fn required_args(&self) -> Option { Some(3) } + fn required_args(&self) -> Option { + Some(3) + } fn try_eval( &self, @@ -625,15 +683,14 @@ impl ExtensionFunction for If { body: Rc, ) -> Result, CompileErr> { let mut allocator = Allocator::new(); - let cond_result = - evaluator.shrink_bodyform( - &mut allocator, - prog_args.clone(), - env, - args[0].clone(), - false, - None - )?; + let cond_result = evaluator.shrink_bodyform( + &mut allocator, + prog_args.clone(), + env, + args[0].clone(), + false, + None, + )?; if let Ok(unquoted) = dequote(body.loc(), cond_result) { if truthy(unquoted) { @@ -643,7 +700,7 @@ impl ExtensionFunction for If { env, args[1].clone(), false, - None + None, ) } else { evaluator.shrink_bodyform( @@ -652,7 +709,7 @@ impl ExtensionFunction for If { env, args[2].clone(), false, - None + None, ) } } else { @@ -696,7 +753,7 @@ impl ExtensionFunction for If { /// substring s start end /// pub struct PreprocessorExtension { - extfuns: HashMap, Rc> + extfuns: HashMap, Rc>, } impl PreprocessorExtension { @@ -707,21 +764,20 @@ impl PreprocessorExtension { (b"c".to_vec(), Cons::new()), (b"f".to_vec(), First::new()), (b"r".to_vec(), Rest::new()), - (b"string?".to_vec(), StringQ::new()), (b"number?".to_vec(), NumberQ::new()), (b"symbol?".to_vec(), SymbolQ::new()), - (b"string->symbol".to_vec(), StringToSymbol::new()), (b"symbol->string".to_vec(), SymbolToString::new()), (b"string->number".to_vec(), StringToNumber::new()), (b"number->string".to_vec(), NumberToString::new()), - (b"string-append".to_vec(), StringAppend::new()), (b"string-length".to_vec(), StringLength::new()), (b"substring".to_vec(), Substring::new()), ]; - PreprocessorExtension { extfuns: HashMap::from(extfuns) } + PreprocessorExtension { + extfuns: HashMap::from(extfuns), + } } } @@ -739,33 +795,24 @@ impl EvalExtension for PreprocessorExtension { if let Some(extfun) = self.extfuns.get(name) { if let Some(n) = extfun.required_args() { if raw_args.len() != n { - return Err(CompileErr(loc.clone(), format!("{} requires {} args", decode_string(name), n))); + return Err(CompileErr( + loc.clone(), + format!("{} requires {} args", decode_string(name), n), + )); } } eprintln!("try function {}", body.to_sexp()); - for (n,v) in env.iter() { + for (n, v) in env.iter() { eprintln!("- {} = {}", decode_string(&n), v.to_sexp()); } - let args = - if extfun.want_interp() { - reify_args( - evaluator, - prog_args.clone(), - env, - raw_args - )? - } else { - raw_args.to_vec() - }; + let args = if extfun.want_interp() { + reify_args(evaluator, prog_args.clone(), env, raw_args)? + } else { + raw_args.to_vec() + }; Ok(Some(extfun.try_eval( - evaluator, - prog_args, - env, - loc, - name, - &args, - body + evaluator, prog_args, env, loc, name, &args, body, )?)) } else { Ok(None) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 2ddb1358d..da6cad96c 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -10,10 +10,12 @@ use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::compiler::compiler::KNOWN_DIALECTS; use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc}; -use crate::compiler::evaluate::{ArgInputs, create_argument_captures, dequote, Evaluator}; +use crate::compiler::evaluate::{create_argument_captures, dequote, ArgInputs, Evaluator}; use crate::compiler::frontend::compile_helperform; -use crate::compiler::sexp::{Atom, decode_string, enlist, NodeSel, parse_sexp, SelectNode, SExp, ThisNode}; use crate::compiler::preprocessor::macros::PreprocessorExtension; +use crate::compiler::sexp::{ + decode_string, enlist, parse_sexp, Atom, NodeSel, SExp, SelectNode, ThisNode, +}; use crate::compiler::srcloc::Srcloc; use crate::util::ErrInto; @@ -31,17 +33,16 @@ impl Preprocessor { Preprocessor { opts: opts.clone(), evaluator: eval, - helpers: Vec::new() + helpers: Vec::new(), } } /// Given a specification of an include file, load up the forms inside it and /// return them (or an error if the file couldn't be read or wasn't a list). - pub fn process_include( - &mut self, - include: IncludeDesc, - ) -> Result>, CompileErr> { - let filename_and_content = self.opts.read_new_file(self.opts.filename(), decode_string(&include.name))?; + pub fn process_include(&mut self, include: IncludeDesc) -> Result>, CompileErr> { + let filename_and_content = self + .opts + .read_new_file(self.opts.filename(), decode_string(&include.name))?; let content = filename_and_content.1; let start_of_file = Srcloc::start(&decode_string(&include.name)); @@ -61,7 +62,7 @@ impl Preprocessor { fn recurse_dependencies( &mut self, includes: &mut Vec, - desc: IncludeDesc + desc: IncludeDesc, ) -> Result<(), CompileErr> { let name_string = decode_string(&desc.name); if KNOWN_DIALECTS.contains_key(&name_string) { @@ -91,23 +92,21 @@ impl Preprocessor { // Check for and apply preprocessor level macros. // This is maximally permissive. - fn expand_macros( - &mut self, - body: Rc - ) -> Result, CompileErr> { + fn expand_macros(&mut self, body: Rc) -> Result, CompileErr> { eprintln!("expand_macros {}", body); - if let SExp::Cons(l,f,r) = body.borrow() { + if let SExp::Cons(l, f, r) = body.borrow() { // First expand inner macros. let first_expanded = self.expand_macros(f.clone())?; let rest_expanded = self.expand_macros(r.clone())?; let new_self = Rc::new(SExp::Cons(l.clone(), first_expanded, rest_expanded)); - if let Ok(NodeSel::Cons((_, name), args)) = NodeSel::Cons( - Atom::Here(()), ThisNode::Here - ).select_nodes(new_self.clone()) { + if let Ok(NodeSel::Cons((_, name), args)) = + NodeSel::Cons(Atom::Here(()), ThisNode::Here).select_nodes(new_self.clone()) + { // See if it's a form that calls one of our macros. for m in self.helpers.iter() { eprintln!("want {} helper {}", decode_string(&name), m.to_sexp()); - if let HelperForm::Defun(_,mdata) = &m { // We record upfront macros + if let HelperForm::Defun(_, mdata) = &m { + // We record upfront macros if mdata.name != name { continue; } @@ -128,7 +127,7 @@ impl Preprocessor { create_argument_captures( &mut macro_arg_env, &ArgInputs::Whole(Rc::new(BodyForm::Quoted(args_borrowed.clone()))), - mdata.args.clone() + mdata.args.clone(), )?; let res = self.evaluator.shrink_bodyform( @@ -137,7 +136,7 @@ impl Preprocessor { ¯o_arg_env, mdata.body.clone(), false, - None + None, )?; if let Ok(unquoted) = dequote(body.loc(), res.clone()) { @@ -158,26 +157,28 @@ impl Preprocessor { } // If it's a defmac (preprocessor level macro), add it to the evaulator. - fn decode_macro( - &mut self, - definition: Rc - ) -> Result, CompileErr> { + fn decode_macro(&mut self, definition: Rc) -> Result, CompileErr> { eprintln!("decode_macro {definition}"); if let Ok(NodeSel::Cons( (defmac_loc, kw), - NodeSel::Cons( - (nl, name), - NodeSel::Cons(args,body) - ) + NodeSel::Cons((nl, name), NodeSel::Cons(args, body)), )) = NodeSel::Cons( Atom::Here(()), NodeSel::Cons( Atom::Here(()), - NodeSel::Cons(ThisNode::Here, ThisNode::Here) - ) - ).select_nodes(definition.clone()) { + NodeSel::Cons(ThisNode::Here, ThisNode::Here), + ), + ) + .select_nodes(definition.clone()) + { let is_defmac = kw == b"defmac"; - if is_defmac || kw == b"defmacro" || kw == b"defun" || kw == b"defun-inline" || kw == b"defconst" || kw == b"defconstant" { + if is_defmac + || kw == b"defmacro" + || kw == b"defun" + || kw == b"defun-inline" + || kw == b"defconst" + || kw == b"defconstant" + { if is_defmac { let target_defun = Rc::new(SExp::Cons( defmac_loc.clone(), @@ -185,10 +186,8 @@ impl Preprocessor { Rc::new(SExp::Cons( nl.clone(), Rc::new(SExp::Atom(nl.clone(), name.clone())), - Rc::new(SExp::Cons( - args.loc(), args.clone(), body.clone() - )) - )) + Rc::new(SExp::Cons(args.loc(), args.clone(), body.clone())), + )), )); eprintln!("target_defun {target_defun}"); if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { @@ -196,7 +195,10 @@ impl Preprocessor { self.evaluator.add_helper(&helper); self.helpers.push(helper); } else { - return Err(CompileErr(definition.loc(), "defmac found but couldn't be converted to function".to_string())); + return Err(CompileErr( + definition.loc(), + "defmac found but couldn't be converted to function".to_string(), + )); } } else if let Some(helper) = compile_helperform(self.opts.clone(), definition)? { self.evaluator.add_helper(&helper); @@ -312,7 +314,7 @@ impl Preprocessor { cmod }; - while let SExp::Cons(_,f,r) = tocompile.borrow() { + while let SExp::Cons(_, f, r) = tocompile.borrow() { let mut lst = self.process_pp_form(includes, f.clone())?; result.append(&mut lst); tocompile = r.clone(); @@ -328,7 +330,7 @@ impl Preprocessor { pub fn preprocess( opts: Rc, includes: &mut Vec, - cmod: Rc + cmod: Rc, ) -> Result>, CompileErr> { let mut p = Preprocessor::new(opts); p.run(includes, cmod) diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 8c2da6bc4..c1b4d009c 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -868,10 +868,9 @@ impl SelectNode, E> for ThisNode { } impl SelectNode<(Srcloc, Vec), (Srcloc, String)> for Atom<()> { - fn select_nodes(&self, s: Rc) -> Result<(Srcloc, Vec), (Srcloc, String)> - { - if let SExp::Atom(loc,name) = s.borrow() { - return Ok((loc.clone(),name.clone())); + fn select_nodes(&self, s: Rc) -> Result<(Srcloc, Vec), (Srcloc, String)> { + if let SExp::Atom(loc, name) = s.borrow() { + return Ok((loc.clone(), name.clone())); } Err((s.loc(), "Not an atom".to_string())) @@ -881,7 +880,7 @@ impl SelectNode<(Srcloc, Vec), (Srcloc, String)> for Atom<()> { impl SelectNode for Atom<&str> { fn select_nodes(&self, s: Rc) -> Result { let Atom::Here(name) = self; - if let Ok((l,n)) = Atom::Here(()).select_nodes(s.clone()) { + if let Ok((l, n)) = Atom::Here(()).select_nodes(s.clone()) { if n == name.as_bytes() { return Ok(l.clone()); } diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 40495c8df..5ccfd906d 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -190,7 +190,8 @@ fn test_defmac_if_extension() { (defmac F (X) (c 1 (FX X))) (F X) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"(9)".to_string()).unwrap(); assert_eq!(res.to_string(), "\"1\""); } @@ -333,7 +334,8 @@ fn test_defmac_stringq() { (defmac is-string (X) (string? X)) (list (is-string X) (is-string \"X\") (is-string 3)) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"()".to_string()).unwrap(); assert_eq!(res.to_string(), "(() 1 ())"); } @@ -345,7 +347,8 @@ fn test_defmac_numberq() { (defmac is-number (X) (number? X)) (list (is-number X) (is-number \"X\") (is-number 3)) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"()".to_string()).unwrap(); assert_eq!(res.to_string(), "(() () 1)"); } @@ -357,7 +360,8 @@ fn test_defmac_symbolq() { (defmac is-symbol (X) (symbol? X)) (list (is-symbol X) (is-symbol \"X\") (is-symbol 3)) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"()".to_string()).unwrap(); assert_eq!(res.to_string(), "(1 () ())"); } @@ -369,7 +373,8 @@ fn test_defmac_string_to_symbol() { (defmac is-symbol (X) (symbol? X)) (list (is-symbol X) (is-symbol \"X\") (is-symbol 3)) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"()".to_string()).unwrap(); assert_eq!(res.to_string(), "(1 () ())"); } @@ -381,7 +386,8 @@ fn test_defmac_string_to_symbol_converts() { (defmac let_pi (code) (qq (let (((unquote (string->symbol \"pi\")) 31415)) (unquote code)))) (let_pi (+ pi X)) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"(5)".to_string()).unwrap(); assert_eq!(res.to_string(), "31420"); } @@ -393,7 +399,8 @@ fn test_defmac_string_needs_conversion() { (defmac let_pi (code) (qq (let ((\"pi\" 31415)) (unquote code)))) (let_pi (+ pi X)) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"(5)".to_string()); assert!(res.is_err()); } @@ -409,7 +416,8 @@ fn test_defmac_string_substr_0() { ) (first-letter-of Xanadu) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"(5999)".to_string()).unwrap(); assert_eq!(res.to_string(), "(\"X\" . 5999)"); } @@ -428,7 +436,8 @@ fn test_defmac_string_substr_bad() { ) (bind-tail-of-symbol 100 test_variable_name (c 9999 variable_name)) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"((87 89 91))".to_string()); assert!(res.is_err()); } @@ -448,7 +457,8 @@ fn test_defmac_string_to_number_0() { ) (add-n-to X_7) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"(31)".to_string()).unwrap(); assert_eq!(res.to_string(), "38"); } @@ -468,7 +478,8 @@ fn test_defmac_string_to_number_bad() { ) (add-n-to X_A) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"(31)".to_string()); assert!(res.is_err()); } @@ -487,7 +498,8 @@ fn test_defmac_number_to_string() { (defun F (Xanadu-6) (+ (with-my-length Xanadu) 99)) (F Q) ) - "}.to_string(); + "} + .to_string(); let res = run_string(&prog, &"(37)".to_string()).unwrap(); assert_eq!(res.to_string(), "136"); } From fdf81e9a7baa819efc4e404bba77adcea92ac48d Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 22 Mar 2023 09:37:36 -0700 Subject: [PATCH 039/196] Tune up, should be ready to pr --- src/compiler/evaluate.rs | 3 +- src/compiler/preprocessor/macros.rs | 117 ++++++++++++++-------------- src/compiler/preprocessor/mod.rs | 24 ++---- src/compiler/sexp.rs | 2 +- 4 files changed, 66 insertions(+), 80 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index f5fcf4ef4..893f20489 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -95,6 +95,7 @@ pub enum ArgInputs { /// I also anticipate using EvalExtensions to analyze and control code shrinking /// during some kinds of optimization. pub trait EvalExtension { + #[allow(clippy::too_many_arguments)] fn try_eval( &self, evaluator: &Evaluator, @@ -943,7 +944,7 @@ impl<'info> Evaluator { env, &l, call_name, - &arguments_to_convert, + arguments_to_convert, body.clone(), )? { return Ok(res); diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index f04f0db36..7e2dbc652 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -69,7 +69,7 @@ fn match_number(body: Rc) -> Result, CompileErr> fn numeric_value(body: Rc) -> Result { match match_number(body.clone())? { - Some(MatchedNumber::MatchedInt(_, n)) => Ok(n.clone()), + Some(MatchedNumber::MatchedInt(_, n)) => Ok(n), Some(MatchedNumber::MatchedHex(_, h)) => Ok(number_from_u8(&h)), _ => Err(CompileErr(body.loc(), "Not a number".to_string())), } @@ -116,6 +116,7 @@ pub trait ExtensionFunction { true } fn required_args(&self) -> Option; + #[allow(clippy::too_many_arguments)] fn try_eval( &self, evaluator: &Evaluator, @@ -131,7 +132,7 @@ pub trait ExtensionFunction { struct StringQ {} impl StringQ { - fn new() -> Rc { + fn create() -> Rc { Rc::new(StringQ {}) } } @@ -154,7 +155,7 @@ impl ExtensionFunction for StringQ { let res = match match_quoted_string(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), Ok(None) => { - return Ok(body.clone()); + return Ok(body); } Err(_) => SExp::Nil(loc.clone()), }; @@ -166,7 +167,7 @@ impl ExtensionFunction for StringQ { struct NumberQ {} impl NumberQ { - fn new() -> Rc { + fn create() -> Rc { Rc::new(NumberQ {}) } } @@ -189,7 +190,7 @@ impl ExtensionFunction for NumberQ { let res = match match_number(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), Ok(None) => { - return Ok(body.clone()); + return Ok(body); } Err(_) => SExp::Nil(loc.clone()), }; @@ -201,7 +202,7 @@ impl ExtensionFunction for NumberQ { struct SymbolQ {} impl SymbolQ { - fn new() -> Rc { + fn create() -> Rc { Rc::new(SymbolQ {}) } } @@ -224,7 +225,7 @@ impl ExtensionFunction for SymbolQ { let res = match match_atom(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), Ok(None) => { - return Ok(body.clone()); + return Ok(body); } Err(_) => SExp::Nil(loc.clone()), }; @@ -236,7 +237,7 @@ impl ExtensionFunction for SymbolQ { struct SymbolToString {} impl SymbolToString { - fn new() -> Rc { + fn create() -> Rc { Rc::new(SymbolToString {}) } } @@ -257,11 +258,11 @@ impl ExtensionFunction for SymbolToString { body: Rc, ) -> Result, CompileErr> { if let Some((loc, value)) = match_atom(args[0].clone())? { - return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( loc, b'\"', value, - )))); + )))) } else { - return Ok(body.clone()); + Ok(body) } } } @@ -269,7 +270,7 @@ impl ExtensionFunction for SymbolToString { struct StringToSymbol {} impl StringToSymbol { - fn new() -> Rc { + fn create() -> Rc { Rc::new(StringToSymbol {}) } } @@ -290,9 +291,9 @@ impl ExtensionFunction for StringToSymbol { body: Rc, ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - return Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc, value)))); + Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc, value)))) } else { - return Ok(body.clone()); + Ok(body) } } } @@ -300,7 +301,7 @@ impl ExtensionFunction for StringToSymbol { struct StringAppend {} impl StringAppend { - fn new() -> Rc { + fn create() -> Rc { Rc::new(StringAppend {}) } } @@ -329,21 +330,21 @@ impl ExtensionFunction for StringAppend { } out_vec.append(&mut value); } else { - return Ok(body.clone()); + return Ok(body); } } - return Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( out_loc.unwrap_or_else(|| body.loc()), b'\"', out_vec, - )))); + )))) } } struct NumberToString {} impl NumberToString { - fn new() -> Rc { + fn create() -> Rc { Rc::new(NumberToString {}) } } @@ -366,9 +367,9 @@ impl ExtensionFunction for NumberToString { let match_res = match_number(args[0].clone())?; let (use_loc, int_val) = match &match_res { Some(MatchedNumber::MatchedInt(l, i)) => (l.clone(), i.clone()), - Some(MatchedNumber::MatchedHex(l, h)) => (l.clone(), number_from_u8(&h)), + Some(MatchedNumber::MatchedHex(l, h)) => (l.clone(), number_from_u8(h)), _ => { - return Ok(body.clone()); + return Ok(body); } }; Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( @@ -382,7 +383,7 @@ impl ExtensionFunction for NumberToString { struct StringToNumber {} impl StringToNumber { - fn new() -> Rc { + fn create() -> Rc { Rc::new(StringToNumber {}) } } @@ -405,11 +406,11 @@ impl ExtensionFunction for StringToNumber { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Ok(cvt_bi) = decode_string(&value).parse::() { Ok(Rc::new(BodyForm::Quoted(SExp::Integer( - loc.clone(), + loc, cvt_bi, )))) } else { - Err(CompileErr(loc.clone(), "bad number".to_string())) + Err(CompileErr(loc, "bad number".to_string())) } } else { Err(CompileErr( @@ -423,7 +424,7 @@ impl ExtensionFunction for StringToNumber { struct StringLength {} impl StringLength { - fn new() -> Rc { + fn create() -> Rc { Rc::new(StringLength {}) } } @@ -446,17 +447,17 @@ impl ExtensionFunction for StringLength { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Some(len_bi) = value.len().to_bigint() { Ok(Rc::new(BodyForm::Quoted(SExp::Integer( - loc.clone(), + loc, len_bi, )))) } else { Err(CompileErr( - loc.clone(), + loc, "Error getting string length".to_string(), )) } } else { - Ok(body.clone()) + Ok(body) } } } @@ -464,7 +465,7 @@ impl ExtensionFunction for StringLength { struct Substring {} impl Substring { - fn new() -> Rc { + fn create() -> Rc { Rc::new(Substring {}) } } @@ -508,7 +509,7 @@ impl ExtensionFunction for Substring { )))) } BodyForm::Quoted(_) => Err(CompileErr(body.loc(), "Not a string".to_string())), - _ => Ok(body.clone()), + _ => Ok(body), } } } @@ -516,7 +517,7 @@ impl ExtensionFunction for Substring { struct List {} impl List { - fn new() -> Rc { + fn create() -> Rc { Rc::new(List {}) } } @@ -548,14 +549,14 @@ impl ExtensionFunction for List { ], )); } - evaluator.shrink_bodyform(&mut allocator, prog_args.clone(), env, res, false, None) + evaluator.shrink_bodyform(&mut allocator, prog_args, env, res, false, None) } } struct Cons {} impl Cons { - fn new() -> Rc { + fn create() -> Rc { Rc::new(Cons {}) } } @@ -582,7 +583,7 @@ impl ExtensionFunction for Cons { Rc::new(b.clone()), )))) } else { - Ok(body.clone()) + Ok(body) } } } @@ -590,7 +591,7 @@ impl ExtensionFunction for Cons { struct First {} impl First { - fn new() -> Rc { + fn create() -> Rc { Rc::new(First {}) } } @@ -616,7 +617,7 @@ impl ExtensionFunction for First { } else if let BodyForm::Quoted(_) = args[0].borrow() { Err(CompileErr(loc.clone(), "bad cons in first".to_string())) } else { - Ok(body.clone()) + Ok(body) } } } @@ -624,7 +625,7 @@ impl ExtensionFunction for First { struct Rest {} impl Rest { - fn new() -> Rc { + fn create() -> Rc { Rc::new(Rest {}) } } @@ -650,7 +651,7 @@ impl ExtensionFunction for Rest { } else if let BodyForm::Quoted(_) = args[0].borrow() { Err(CompileErr(loc.clone(), "bad cons in rest".to_string())) } else { - Ok(body.clone()) + Ok(body) } } } @@ -658,7 +659,7 @@ impl ExtensionFunction for Rest { struct If {} impl If { - fn new() -> Rc { + fn create() -> Rc { Rc::new(If {}) } } @@ -696,7 +697,7 @@ impl ExtensionFunction for If { if truthy(unquoted) { evaluator.shrink_bodyform( &mut allocator, - prog_args.clone(), + prog_args, env, args[1].clone(), false, @@ -705,7 +706,7 @@ impl ExtensionFunction for If { } else { evaluator.shrink_bodyform( &mut allocator, - prog_args.clone(), + prog_args, env, args[2].clone(), false, @@ -759,21 +760,21 @@ pub struct PreprocessorExtension { impl PreprocessorExtension { pub fn new() -> Self { let extfuns = [ - (b"if".to_vec(), If::new()), - (b"list".to_vec(), List::new()), - (b"c".to_vec(), Cons::new()), - (b"f".to_vec(), First::new()), - (b"r".to_vec(), Rest::new()), - (b"string?".to_vec(), StringQ::new()), - (b"number?".to_vec(), NumberQ::new()), - (b"symbol?".to_vec(), SymbolQ::new()), - (b"string->symbol".to_vec(), StringToSymbol::new()), - (b"symbol->string".to_vec(), SymbolToString::new()), - (b"string->number".to_vec(), StringToNumber::new()), - (b"number->string".to_vec(), NumberToString::new()), - (b"string-append".to_vec(), StringAppend::new()), - (b"string-length".to_vec(), StringLength::new()), - (b"substring".to_vec(), Substring::new()), + (b"if".to_vec(), If::create()), + (b"list".to_vec(), List::create()), + (b"c".to_vec(), Cons::create()), + (b"f".to_vec(), First::create()), + (b"r".to_vec(), Rest::create()), + (b"string?".to_vec(), StringQ::create()), + (b"number?".to_vec(), NumberQ::create()), + (b"symbol?".to_vec(), SymbolQ::create()), + (b"string->symbol".to_vec(), StringToSymbol::create()), + (b"symbol->string".to_vec(), SymbolToString::create()), + (b"string->number".to_vec(), StringToNumber::create()), + (b"number->string".to_vec(), NumberToString::create()), + (b"string-append".to_vec(), StringAppend::create()), + (b"string-length".to_vec(), StringLength::create()), + (b"substring".to_vec(), Substring::create()), ]; PreprocessorExtension { extfuns: HashMap::from(extfuns), @@ -802,10 +803,6 @@ impl EvalExtension for PreprocessorExtension { } } - eprintln!("try function {}", body.to_sexp()); - for (n, v) in env.iter() { - eprintln!("- {} = {}", decode_string(&n), v.to_sexp()); - } let args = if extfun.want_interp() { reify_args(evaluator, prog_args.clone(), env, raw_args)? } else { diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index da6cad96c..d8af94fc5 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -93,7 +93,6 @@ impl Preprocessor { // Check for and apply preprocessor level macros. // This is maximally permissive. fn expand_macros(&mut self, body: Rc) -> Result, CompileErr> { - eprintln!("expand_macros {}", body); if let SExp::Cons(l, f, r) = body.borrow() { // First expand inner macros. let first_expanded = self.expand_macros(f.clone())?; @@ -104,18 +103,12 @@ impl Preprocessor { { // See if it's a form that calls one of our macros. for m in self.helpers.iter() { - eprintln!("want {} helper {}", decode_string(&name), m.to_sexp()); if let HelperForm::Defun(_, mdata) = &m { // We record upfront macros if mdata.name != name { continue; } - eprintln!("expanding macro {}", m.to_sexp()); - for h in self.helpers.iter() { - eprintln!("- {}", decode_string(h.name())); - } - // as inline defuns because they're closest to that // semantically. let mut allocator = Allocator::new(); @@ -139,12 +132,10 @@ impl Preprocessor { None, )?; - if let Ok(unquoted) = dequote(body.loc(), res.clone()) { - eprintln!("expand macro {}", unquoted); + if let Ok(unquoted) = dequote(body.loc(), res) { return Ok(unquoted); } else { - eprintln!("bad expand? {}", res.to_sexp()); - todo!(); + return Err(CompileErr(body.loc(), "Failed to fully evaluate macro".to_string())); } } } @@ -158,7 +149,6 @@ impl Preprocessor { // If it's a defmac (preprocessor level macro), add it to the evaulator. fn decode_macro(&mut self, definition: Rc) -> Result, CompileErr> { - eprintln!("decode_macro {definition}"); if let Ok(NodeSel::Cons( (defmac_loc, kw), NodeSel::Cons((nl, name), NodeSel::Cons(args, body)), @@ -182,16 +172,14 @@ impl Preprocessor { if is_defmac { let target_defun = Rc::new(SExp::Cons( defmac_loc.clone(), - Rc::new(SExp::atom_from_string(defmac_loc.clone(), "defun")), + Rc::new(SExp::atom_from_string(defmac_loc, "defun")), Rc::new(SExp::Cons( nl.clone(), - Rc::new(SExp::Atom(nl.clone(), name.clone())), - Rc::new(SExp::Cons(args.loc(), args.clone(), body.clone())), + Rc::new(SExp::Atom(nl, name)), + Rc::new(SExp::Cons(args.loc(), args.clone(), body)), )), )); - eprintln!("target_defun {target_defun}"); if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { - eprintln!("add helper {}", helper.to_sexp()); self.evaluator.add_helper(&helper); self.helpers.push(helper); } else { @@ -350,7 +338,7 @@ pub fn gather_dependencies( let mut p = Preprocessor::new(no_stdenv_opts); let loc = Srcloc::start(real_input_path); - let parsed = parse_sexp(loc.clone(), file_content.bytes())?; + let parsed = parse_sexp(loc, file_content.bytes())?; if parsed.is_empty() { return Ok(vec![]); diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index c1b4d009c..4e9dcb2d0 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -882,7 +882,7 @@ impl SelectNode for Atom<&str> { let Atom::Here(name) = self; if let Ok((l, n)) = Atom::Here(()).select_nodes(s.clone()) { if n == name.as_bytes() { - return Ok(l.clone()); + return Ok(l); } } From 8237c6af5f97b6df7db590e87629abec9ca3e145 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 22 Mar 2023 09:51:30 -0700 Subject: [PATCH 040/196] Fmt --- src/compiler/preprocessor/macros.rs | 15 +++------------ src/compiler/preprocessor/mod.rs | 5 ++++- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 7e2dbc652..28abf435d 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -405,10 +405,7 @@ impl ExtensionFunction for StringToNumber { ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Ok(cvt_bi) = decode_string(&value).parse::() { - Ok(Rc::new(BodyForm::Quoted(SExp::Integer( - loc, - cvt_bi, - )))) + Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc, cvt_bi)))) } else { Err(CompileErr(loc, "bad number".to_string())) } @@ -446,15 +443,9 @@ impl ExtensionFunction for StringLength { ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Some(len_bi) = value.len().to_bigint() { - Ok(Rc::new(BodyForm::Quoted(SExp::Integer( - loc, - len_bi, - )))) + Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc, len_bi)))) } else { - Err(CompileErr( - loc, - "Error getting string length".to_string(), - )) + Err(CompileErr(loc, "Error getting string length".to_string())) } } else { Ok(body) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index d8af94fc5..77d77d94d 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -135,7 +135,10 @@ impl Preprocessor { if let Ok(unquoted) = dequote(body.loc(), res) { return Ok(unquoted); } else { - return Err(CompileErr(body.loc(), "Failed to fully evaluate macro".to_string())); + return Err(CompileErr( + body.loc(), + "Failed to fully evaluate macro".to_string(), + )); } } } From 6e7d08c1bfd9a3aaca0182c8321c12fb557d6a5a Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 25 Apr 2023 14:58:27 -0700 Subject: [PATCH 041/196] Pull in the merging of lambdas with desugaring --- src/compiler/codegen.rs | 172 ++++++++++++++++++++++----------- src/compiler/compiler.rs | 4 +- src/compiler/comptypes.rs | 27 ++---- src/compiler/evaluate.rs | 51 ++++++++-- src/compiler/frontend.rs | 17 +--- src/compiler/lambda.rs | 70 +++----------- src/compiler/rename.rs | 24 +---- src/tests/compiler/compiler.rs | 49 +++++++++- src/tests/compiler/repl.rs | 27 ++++++ 9 files changed, 260 insertions(+), 181 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index dcb1ba7b9..921fa46ad 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -22,7 +22,7 @@ use crate::compiler::evaluate::{Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::frontend::compile_bodyform; use crate::compiler::gensym::gensym; use crate::compiler::inline::{replace_in_inline, synthesize_args}; -use crate::compiler::lambda::{compose_constant_function_env, lambda_codegen}; +use crate::compiler::lambda::lambda_codegen; use crate::compiler::optimize::optimize_expr; use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; @@ -181,18 +181,86 @@ fn create_name_lookup_( } } +fn is_defun_in_codegen(compiler: &PrimaryCodegen, name: &[u8]) -> bool { + // Check for an input defun that matches the name. + for h in compiler.original_helpers.iter() { + if matches!(h, HelperForm::Defun(false, _)) && h.name() == name { + return true; + } + } + + false +} + +fn make_list(loc: Srcloc, elements: Vec>) -> Rc { + let mut res = Rc::new(SExp::Nil(loc.clone())); + for e in elements.iter().rev() { + res = Rc::new(primcons(loc.clone(), e.clone(), res)); + } + res +} + +// +// Write an expression that conses the left env. +// +// (list (q . 2) (c (q . 1) n) (list (q . 4) (c (q . 1) 2) (q . 1))) +// +// Something like: +// (apply (quoted (expanded n)) (cons (quoted (expanded 2)) given-args)) +// +fn lambda_for_defun(loc: Srcloc, lookup: Rc) -> Rc { + let one_atom = Rc::new(SExp::Atom(loc.clone(), vec![1])); + let two_atom = Rc::new(SExp::Atom(loc.clone(), vec![2])); + let apply_atom = two_atom.clone(); + let cons_atom = Rc::new(SExp::Atom(loc.clone(), vec![4])); + make_list( + loc.clone(), + vec![ + Rc::new(primquote(loc.clone(), apply_atom)), + Rc::new(primcons( + loc.clone(), + Rc::new(primquote(loc.clone(), one_atom.clone())), + lookup, + )), + make_list( + loc.clone(), + vec![ + Rc::new(primquote(loc.clone(), cons_atom)), + Rc::new(primcons( + loc.clone(), + Rc::new(primquote(loc.clone(), one_atom.clone())), + two_atom, + )), + Rc::new(primquote(loc, one_atom)), + ], + ), + ], + ) +} + fn create_name_lookup( compiler: &PrimaryCodegen, l: Srcloc, name: &[u8], + as_variable: bool, ) -> Result, CompileErr> { compiler .constants .get(name) .map(|x| Ok(x.clone())) .unwrap_or_else(|| { - create_name_lookup_(l.clone(), name, compiler.env.clone(), compiler.env.clone()) - .map(|i| Rc::new(SExp::Integer(l.clone(), i.to_bigint().unwrap()))) + create_name_lookup_(l.clone(), name, compiler.env.clone(), compiler.env.clone()).map( + |i| { + // Determine if it's a defun. If so we can ensure that it's + // callable like a lambda by repeating the left env into it. + let find_program = Rc::new(SExp::Integer(l.clone(), i.to_bigint().unwrap())); + if as_variable && is_defun_in_codegen(compiler, name) { + lambda_for_defun(l.clone(), find_program) + } else { + find_program + } + }, + ) }) } @@ -220,7 +288,7 @@ pub fn get_callable( SExp::Atom(l, name) => { let macro_def = compiler.macros.get(name); let inline = compiler.inlines.get(name); - let defun = create_name_lookup(compiler, l.clone(), name); + let defun = create_name_lookup(compiler, l.clone(), name, false); let prim = get_prim(l.clone(), compiler.prims.clone(), name); let atom_is_com = *name == "com".as_bytes().to_vec(); let atom_is_at = *name == "@".as_bytes().to_vec(); @@ -524,7 +592,7 @@ pub fn generate_expr_code( Rc::new(SExp::Integer(l.clone(), bi_one())), )) } else { - create_name_lookup(compiler, l.clone(), atom) + create_name_lookup(compiler, l.clone(), atom, true) .map(|f| Ok(CompiledCode(l.clone(), f))) .unwrap_or_else(|_| { // Pass through atoms that don't look up on behalf of @@ -570,34 +638,7 @@ pub fn generate_expr_code( compile_call(allocator, runner, l.clone(), opts, compiler, list.to_vec()) } } - BodyForm::Mod(_, true, program) => { - let parent_env = compose_constant_function_env(compiler)?; - let env = Rc::new(SExp::Cons( - program.args.loc(), - parent_env, - program.args.clone(), - )); - let opts_with_env = opts - .set_start_env(Some(env)) - .set_in_defun(true) - .set_code_generator(compiler.clone()); - let code = codegen( - allocator, - runner, - opts_with_env, - program, - &mut HashMap::new(), - )?; - Ok(CompiledCode( - program.loc.clone(), - Rc::new(SExp::Cons( - program.loc.clone(), - Rc::new(SExp::Atom(program.loc.clone(), vec![1])), - Rc::new(code), - )), - )) - } - BodyForm::Mod(_, false, program) => { + BodyForm::Mod(_, program) => { // A mod form yields the compiled code. let without_env = opts.set_start_env(None).set_in_defun(false); let code = codegen(allocator, runner, without_env, program, &mut HashMap::new())?; @@ -610,17 +651,6 @@ pub fn generate_expr_code( )), )) } - BodyForm::Lambda(ldata) => { - let desugared_lambda_callsite = lambda_codegen(ldata)?; - let result = generate_expr_code( - allocator, - runner, - opts, - compiler, - Rc::new(desugared_lambda_callsite), - )?; - Ok(result) - } _ => Err(CompileErr( expr.loc(), format!("don't know how to compile {}", expr.to_sexp()), @@ -814,11 +844,11 @@ pub fn hoist_body_let_binding( outer_context: Option>, args: Rc, body: Rc, -) -> (Vec, Rc) { +) -> Result<(Vec, Rc), CompileErr> { match body.borrow() { BodyForm::Let(LetFormKind::Sequential, letdata) => { if letdata.bindings.is_empty() { - return (vec![], letdata.body.clone()); + return Ok((vec![], letdata.body.clone())); } // If we're here, we're in the middle of hoisting. @@ -861,7 +891,7 @@ pub fn hoist_body_let_binding( let mut revised_bindings = Vec::new(); for b in letdata.bindings.iter() { let (mut new_helpers, new_binding) = - hoist_body_let_binding(outer_context.clone(), args.clone(), b.body.clone()); + hoist_body_let_binding(outer_context.clone(), args.clone(), b.body.clone())?; out_defuns.append(&mut new_helpers); revised_bindings.push(Rc::new(Binding { loc: b.loc.clone(), @@ -907,24 +937,52 @@ pub fn hoist_body_let_binding( call_args.append(&mut let_args); let final_call = BodyForm::Call(letdata.loc.clone(), call_args); - (out_defuns, Rc::new(final_call)) + Ok((out_defuns, Rc::new(final_call))) } BodyForm::Call(l, list) => { let mut vres = Vec::new(); let mut new_call_list = vec![list[0].clone()]; for i in list.iter().skip(1) { let (new_helper, new_arg) = - hoist_body_let_binding(outer_context.clone(), args.clone(), i.clone()); + hoist_body_let_binding(outer_context.clone(), args.clone(), i.clone())?; new_call_list.push(new_arg); vres.append(&mut new_helper.clone()); } - (vres, Rc::new(BodyForm::Call(l.clone(), new_call_list))) + Ok((vres, Rc::new(BodyForm::Call(l.clone(), new_call_list)))) + } + BodyForm::Lambda(letdata) => { + let new_function_args = Rc::new(SExp::Cons( + letdata.loc.clone(), + letdata.capture_args.clone(), + letdata.args.clone() + )); + let new_function_name = gensym(b"lambda".to_vec()); + let (mut new_helpers_from_body, new_body) = hoist_body_let_binding( + Some(new_function_args.clone()), + new_function_args.clone(), + letdata.body.clone() + )?; + let new_expr = lambda_codegen(&new_function_name, &letdata)?; + let function = HelperForm::Defun( + false, + DefunData { + loc: letdata.loc.clone(), + name: new_function_name, + kw: letdata.kw.clone(), + nl: letdata.args.loc(), + orig_args: new_function_args.clone(), + args: new_function_args, + body: new_body + } + ); + new_helpers_from_body.push(function); + Ok((new_helpers_from_body, Rc::new(new_expr))) } - _ => (Vec::new(), body.clone()), + _ => Ok((Vec::new(), body.clone())) } } -pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Vec { +pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Result, CompileErr> { let mut result = helpers.to_owned(); let mut i = 0; @@ -937,7 +995,7 @@ pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Vec { None }; let helper_result = - hoist_body_let_binding(context, defun.args.clone(), defun.body.clone()); + hoist_body_let_binding(context, defun.args.clone(), defun.body.clone())?; let hoisted_helpers = helper_result.0; let hoisted_body = helper_result.1.clone(); @@ -966,7 +1024,7 @@ pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Vec { } } - result + Ok(result) } fn start_codegen( @@ -1113,7 +1171,11 @@ fn start_codegen( }; code_generator.to_process = program.helpers.clone(); - code_generator.original_helpers = program.helpers.clone(); + // Ensure that we have the synthesis of the previous codegen's helpers and + // The ones provided with the new form if any. + let mut combined_helpers_for_codegen = program.helpers.clone(); + combined_helpers_for_codegen.append(&mut code_generator.original_helpers); + code_generator.original_helpers = combined_helpers_for_codegen; code_generator.final_expr = program.exp; Ok(code_generator) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 7639f88b5..5dc6c6735 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -166,14 +166,14 @@ pub fn compile_pre_forms( }; // Transform let bindings, merging nested let scopes with the top namespace - let hoisted_bindings = hoist_body_let_binding(None, p1.args.clone(), p1.exp.clone()); + let hoisted_bindings = hoist_body_let_binding(None, p1.args.clone(), p1.exp.clone())?; let mut new_helpers = hoisted_bindings.0; let expr = hoisted_bindings.1; // expr is the let-hoisted program // TODO: Distinguish the frontend_helpers and the hoisted_let helpers for later stages let mut combined_helpers = p1.helpers.clone(); combined_helpers.append(&mut new_helpers); - let combined_helpers = process_helper_let_bindings(&combined_helpers); + let combined_helpers = process_helper_let_bindings(&combined_helpers)?; let p2 = CompileForm { loc: p1.loc.clone(), diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index b86af066b..b4cef42cf 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -1,4 +1,3 @@ -use std::borrow::Borrow; use std::collections::HashMap; use std::collections::HashSet; use std::rc::Rc; @@ -166,9 +165,7 @@ pub enum BodyForm { /// (mod ...) can be used in chialisp as an expression, in which it returns /// the compiled code. Here, it contains a CompileForm, which represents /// the full significant input of a program (yielded by frontend()). - /// If the bool is true, then the module takes a environment when applied in - /// the same shape as the host program. - Mod(Srcloc, bool, CompileForm), + Mod(Srcloc, CompileForm), /// A lambda form (lambda (...) ...) /// /// The lambda arguments are in two parts: @@ -616,15 +613,11 @@ fn compose_lambda_serialized_form(ldata: &LambdaData) -> Rc { } else { ldata.args.clone() }; - let rest_of_body = if let SExp::Cons(_, _, after_kw) = ldata.body.to_sexp().borrow() { - if let SExp::Cons(_, _, after_args) = after_kw.borrow() { - after_args.clone() - } else { - Rc::new(SExp::Nil(ldata.loc.clone())) - } - } else { + let rest_of_body = Rc::new(SExp::Cons( + ldata.loc.clone(), + ldata.body.to_sexp(), Rc::new(SExp::Nil(ldata.loc.clone())) - }; + )); Rc::new(SExp::Cons( ldata.loc.clone(), @@ -641,7 +634,7 @@ impl BodyForm { BodyForm::Quoted(a) => a.loc(), BodyForm::Call(loc, _) => loc.clone(), BodyForm::Value(a) => a.loc(), - BodyForm::Mod(kl, _, program) => kl.ext(&program.loc), + BodyForm::Mod(kl, program) => kl.ext(&program.loc), BodyForm::Lambda(ldata) => ldata.loc.ext(&ldata.body.loc()), } } @@ -685,13 +678,9 @@ impl BodyForm { let converted: Vec> = exprs.iter().map(|x| x.to_sexp()).collect(); Rc::new(list_to_cons(loc.clone(), &converted)) } - BodyForm::Mod(loc, left_env, program) => Rc::new(SExp::Cons( + BodyForm::Mod(loc, program) => Rc::new(SExp::Cons( loc.clone(), - if *left_env { - Rc::new(SExp::Atom(loc.clone(), b"mod+".to_vec())) - } else { - Rc::new(SExp::Atom(loc.clone(), b"mod".to_vec())) - }, + Rc::new(SExp::Atom(loc.clone(), b"mod".to_vec())), program.to_sexp(), )), BodyForm::Lambda(ldata) => compose_lambda_serialized_form(ldata), diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 3ef292940..cb93e4302 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -13,8 +13,7 @@ use crate::compiler::clvm::run; use crate::compiler::codegen::codegen; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ - Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, LambdaData, LetData, - LetFormKind, + Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, LambdaData, LetData, LetFormKind, }; use crate::compiler::frontend::frontend; use crate::compiler::runtypes::RunFailure; @@ -694,13 +693,11 @@ impl<'info> Evaluator { only_inline, )?; if let BodyForm::Lambda(ldata) = evaluated_prog.borrow() { - if let BodyForm::Mod(_, _, cf) = ldata.body.borrow() { - return Ok(Some(LambdaApply { - lambda: ldata.clone(), - body: cf.exp.clone(), - env: evaluated_env, - })); - } + return Ok(Some(LambdaApply { + lambda: ldata.clone(), + body: ldata.body.clone(), + env: evaluated_env, + })); } } @@ -1096,6 +1093,31 @@ impl<'info> Evaluator { }))) } + fn get_function(&self, name: &[u8]) -> Option> { + for h in self.helpers.iter() { + if let HelperForm::Defun(false, dd) = &h { + if name == h.name() { + return Some(Box::new(dd.clone())); + } + } + } + + None + } + + fn create_mod_for_fun(&self, l: &Srcloc, function: &DefunData) -> Rc { + Rc::new(BodyForm::Mod( + l.clone(), + CompileForm { + loc: l.clone(), + include_forms: Vec::new(), + args: function.args.clone(), + helpers: self.helpers.clone(), + exp: function.body.clone(), + }, + )) + } + // A frontend language evaluator and minifier fn shrink_bodyform_visited( &self, @@ -1166,6 +1188,15 @@ impl<'info> Evaluator { literal_args, only_inline, ) + } else if let Some(function) = self.get_function(name) { + self.shrink_bodyform_visited( + allocator, + &mut visited, + prog_args, + env, + self.create_mod_for_fun(l, function.borrow()), + only_inline, + ) } else { env.get(name) .map(|x| { @@ -1251,7 +1282,7 @@ impl<'info> Evaluator { )), } } - BodyForm::Mod(_, _, program) => { + BodyForm::Mod(_, program) => { // A mod form yields the compiled code. let code = codegen( allocator, diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index d627e2f1a..e15427ec6 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -64,17 +64,7 @@ fn collect_used_names_bodyform(body: &BodyForm) -> Vec> { } result } - BodyForm::Mod(_, false, _) => vec![], - BodyForm::Mod(_, true, form) => { - let mut result = Vec::new(); - for h in form.helpers.iter() { - let mut helper_uses = collect_used_names_helperform(h); - result.append(&mut helper_uses); - } - let mut body_uses = collect_used_names_bodyform(form.exp.borrow()); - result.append(&mut body_uses); - result - } + BodyForm::Mod(_, _) => vec![], BodyForm::Lambda(ldata) => { let mut capture_names = collect_used_names_bodyform(ldata.captures.borrow()); capture_names.append(&mut collect_used_names_bodyform(ldata.body.borrow())); @@ -339,10 +329,7 @@ pub fn compile_bodyform( qq_to_expression(opts, Rc::new(quote_body)) } else if *atom_name == b"mod" { let subparse = frontend(opts, &[body.clone()])?; - Ok(BodyForm::Mod(op.loc(), false, subparse)) - } else if *atom_name == b"mod+" { - let subparse = frontend(opts, &[body.clone()])?; - Ok(BodyForm::Mod(op.loc(), true, subparse)) + Ok(BodyForm::Mod(op.loc(), subparse)) } else if *atom_name == b"lambda" { handle_lambda(opts, Some(l.clone()), &v) } else { diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index afb6ec7c6..905d7212f 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -1,22 +1,13 @@ use std::borrow::Borrow; use std::rc::Rc; -use num_bigint::ToBigInt; - use crate::compiler::clvm::truthy; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, LambdaData, PrimaryCodegen}; -use crate::compiler::evaluate::{make_operator1, make_operator2}; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, LambdaData}; +use crate::compiler::evaluate::make_operator2; use crate::compiler::frontend::compile_bodyform; -use crate::compiler::sexp::{enlist, SExp}; +use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; -pub fn compose_constant_function_env(compiler: &PrimaryCodegen) -> Result, CompileErr> { - match compiler.env.borrow() { - SExp::Cons(_, left, _) => Ok(left.clone()), - _ => Ok(Rc::new(SExp::Nil(compiler.env.loc()))), - } -} - fn make_captures(opts: Rc, sexp: Rc) -> Result, CompileErr> { if let SExp::Cons(l, f, r) = sexp.borrow() { Ok(Rc::new(make_operator2( @@ -98,23 +89,12 @@ fn make_list(loc: Srcloc, args: &[BodyForm]) -> BodyForm { // // Yields: // -// M = (mod ((captures) arguments) (body)) // (list 2 -// (c 1 (mod ((captures) arguments) body)) -// (list 4 (c 1 (@ 2)) (list 4 (c 1 compose_captures) @)) +// (c 1 ) +// (list 4 (list 4 (c 1 compose_captures) @)) // ) // -pub fn lambda_codegen(ldata: &LambdaData) -> Result { - // Requires captures - // Code to retrieve the left env. - let retrieve_left_env = Rc::new(make_operator1( - &ldata.loc, - "@".to_string(), - Rc::new(BodyForm::Value(SExp::Integer( - ldata.loc.clone(), - 2_u32.to_bigint().unwrap(), - ))), - )); +pub fn lambda_codegen(name: &[u8], ldata: &LambdaData) -> Result { // Code to retrieve and quote the captures. let quote_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![1])); let apply_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![2])); @@ -126,25 +106,17 @@ pub fn lambda_codegen(ldata: &LambdaData) -> Result { Rc::new(quote_atom.clone()), ldata.captures.clone(), ); - let quoted_code = make_cons( - ldata.loc.clone(), - Rc::new(quote_atom.clone()), - ldata.body.clone(), - ); let lambda_output = make_list( ldata.loc.clone(), &[ apply_atom, - quoted_code, - make_list( + make_cons( ldata.loc.clone(), - &[ - cons_atom.clone(), - make_cons(ldata.loc.clone(), Rc::new(quote_atom), retrieve_left_env), - make_list(ldata.loc.clone(), &[cons_atom, compose_captures, whole_env]), - ], + Rc::new(quote_atom.clone()), + Rc::new(BodyForm::Value(SExp::Atom(ldata.loc.clone(), name.to_vec()))) ), + make_list(ldata.loc.clone(), &[cons_atom, compose_captures, whole_env]), ], ); Ok(lambda_output) @@ -163,28 +135,10 @@ pub fn handle_lambda( } let found = find_and_compose_captures(opts.clone(), &v[0])?; - let combined_captures_and_args = Rc::new(SExp::Cons( - found.args.loc(), - found.capture_args.clone(), - found.args.clone(), - )); - - let rolled_elements_vec: Vec> = v.iter().skip(1).map(|x| Rc::new(x.clone())).collect(); - let body_list = enlist(v[0].loc(), rolled_elements_vec); - - // Make the mod form - let mod_form_data = Rc::new(SExp::Cons( - v[0].loc(), - Rc::new(SExp::atom_from_string(v[0].loc(), "mod+")), - Rc::new(SExp::Cons( - found.args.loc(), - combined_captures_and_args, - Rc::new(body_list), - )), - )); // Requires captures - let subparse = compile_bodyform(opts, mod_form_data)?; + let subparse = compile_bodyform(opts, Rc::new(v[1].clone()))?; + Ok(BodyForm::Lambda(LambdaData { loc: v[0].loc(), kw: kw_loc, diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 074aef1bf..9d3e991c3 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -118,24 +118,6 @@ fn make_binding_unique(b: &Binding) -> (Vec, Binding) { ) } -pub fn lambda_body_rename(namemap: &HashMap, Vec>, lambda_body: &BodyForm) -> BodyForm { - if let BodyForm::Mod(l, true, compiled) = lambda_body { - let new_args = rename_in_cons(namemap, compiled.args.clone()); - let new_body = rename_in_bodyform(namemap, compiled.exp.clone()); - BodyForm::Mod( - l.clone(), - true, - CompileForm { - args: new_args, - exp: Rc::new(new_body), - ..compiled.clone() - }, - ) - } else { - lambda_body.clone() - } -} - fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> BodyForm { match b.borrow() { BodyForm::Let(kind, letdata) => { @@ -187,12 +169,12 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B BodyForm::Call(l.clone(), new_vs) } - BodyForm::Mod(l, left_env, prog) => BodyForm::Mod(l.clone(), *left_env, prog.clone()), + BodyForm::Mod(l, prog) => BodyForm::Mod(l.clone(), prog.clone()), BodyForm::Lambda(ldata) => { let renamed_capture_inputs = Rc::new(rename_in_bodyform(namemap, ldata.captures.clone())); let renamed_capture_outputs = rename_in_cons(namemap, ldata.capture_args.clone()); - let renamed_body = lambda_body_rename(namemap, ldata.body.borrow()); + let renamed_body = rename_in_bodyform(namemap, ldata.body.clone()); BodyForm::Lambda(LambdaData { captures: renamed_capture_inputs, capture_args: renamed_capture_outputs, @@ -286,7 +268,7 @@ fn rename_args_bodyform(b: &BodyForm) -> BodyForm { .collect(); BodyForm::Call(l.clone(), new_vs) } - BodyForm::Mod(l, left_env, program) => BodyForm::Mod(l.clone(), *left_env, program.clone()), + BodyForm::Mod(l, program) => BodyForm::Mod(l.clone(), program.clone()), BodyForm::Lambda(ldata) => BodyForm::Lambda(ldata.clone()), } } diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index b778243c7..db95a759d 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1244,7 +1244,24 @@ fn test_lambda_with_capture() { } #[test] -fn test_lambda_in_let() { +fn test_lambda_in_let_0() { + let prog = indoc! {" +(mod (A) + (include *standard-cl-21*) + (defun FOO (Z) + (let ((Q (* 2 Z))) + (lambda ((& Q)) (- 100 Q)) + ) + ) + (a (FOO A) ()) + )"} + .to_string(); + let res = run_string(&prog, &"(5)".to_string()).unwrap(); + assert_eq!(res.to_string(), "90"); +} + +#[test] +fn test_lambda_in_let_1() { let prog = indoc! {" (mod (A B) (include *standard-cl-21*) @@ -1533,6 +1550,36 @@ fn test_lambda_as_argument_to_macro_with_inner_let() { assert_eq!(res.to_string(), "(30 11 20)"); } +#[test] +fn test_treat_function_name_as_value() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + (defun G (X) (* 2 X)) + (defun F (X) (G (+ 1 X))) + (a F (list X)) +) + "} + .to_string(); + let res = run_string(&prog, &"(99)".to_string()).expect("should compile"); + assert_eq!(res.to_string(), "200"); +} + +#[test] +fn test_treat_function_name_as_value_filter() { + let prog = indoc! {" + (mod L + (include *standard-cl-21*) + (defun greater-than-3 (X) (> X 3)) + (defun filter (F L) (let ((rest (filter F (r L)))) (if L (if (a F (list (f L))) (c (f L) rest) rest) ()))) + (filter greater-than-3 L) + ) + "} + .to_string(); + let res = run_string(&prog, &"(1 2 3 4 5)".to_string()).expect("should compile"); + assert_eq!(res.to_string(), "(4 5)"); +} + #[test] fn test_inline_in_assign_not_actually_recursive() { let prog = indoc! {" diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index 80b608e3e..65b384c62 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -302,6 +302,33 @@ fn test_eval_list_partially_evaluated_xyz() { ); } +#[test] +fn test_defun_value_in_repl_0() { + assert_eq!( + test_repl_outcome(vec![ + "(defun greater-than-3 (X) (> X 3))", + "(a greater-than-3 (list 5))" + ]) + .unwrap() + .unwrap(), + "(q . 1)" + ); +} + +#[test] +fn test_defun_value_repl_map() { + assert_eq!( + test_repl_outcome(vec![ + "(defun greater-than-3 (X) (> X 3))", + "(defun map (F L) (if L (c (a F (list (f L))) (map F (r L))) ()))", + "(map greater-than-3 (list 1 2 3 4 5))" + ]) + .unwrap() + .unwrap(), + "(q () () () 1 1)" + ); +} + #[test] fn test_lambda_eval_5() { assert_eq!( From 304d988c4e770f309e83cda7ee57b44a7d9fd7b6 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 25 Apr 2023 15:47:56 -0700 Subject: [PATCH 042/196] fmt + clippy --- src/compiler/codegen.rs | 12 ++++++------ src/compiler/comptypes.rs | 2 +- src/compiler/evaluate.rs | 3 ++- src/compiler/lambda.rs | 7 +++++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 921fa46ad..5fef00c5f 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -954,15 +954,15 @@ pub fn hoist_body_let_binding( let new_function_args = Rc::new(SExp::Cons( letdata.loc.clone(), letdata.capture_args.clone(), - letdata.args.clone() + letdata.args.clone(), )); let new_function_name = gensym(b"lambda".to_vec()); let (mut new_helpers_from_body, new_body) = hoist_body_let_binding( Some(new_function_args.clone()), new_function_args.clone(), - letdata.body.clone() + letdata.body.clone(), )?; - let new_expr = lambda_codegen(&new_function_name, &letdata)?; + let new_expr = lambda_codegen(&new_function_name, letdata)?; let function = HelperForm::Defun( false, DefunData { @@ -972,13 +972,13 @@ pub fn hoist_body_let_binding( nl: letdata.args.loc(), orig_args: new_function_args.clone(), args: new_function_args, - body: new_body - } + body: new_body, + }, ); new_helpers_from_body.push(function); Ok((new_helpers_from_body, Rc::new(new_expr))) } - _ => Ok((Vec::new(), body.clone())) + _ => Ok((Vec::new(), body.clone())), } } diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index b4cef42cf..6e1105b0e 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -616,7 +616,7 @@ fn compose_lambda_serialized_form(ldata: &LambdaData) -> Rc { let rest_of_body = Rc::new(SExp::Cons( ldata.loc.clone(), ldata.body.to_sexp(), - Rc::new(SExp::Nil(ldata.loc.clone())) + Rc::new(SExp::Nil(ldata.loc.clone())), )); Rc::new(SExp::Cons( diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index cb93e4302..b32786d58 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -13,7 +13,8 @@ use crate::compiler::clvm::run; use crate::compiler::codegen::codegen; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ - Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, LambdaData, LetData, LetFormKind, + Binding, BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, LambdaData, + LetData, LetFormKind, }; use crate::compiler::frontend::frontend; use crate::compiler::runtypes::RunFailure; diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 905d7212f..d84a3e550 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -113,8 +113,11 @@ pub fn lambda_codegen(name: &[u8], ldata: &LambdaData) -> Result Date: Sat, 20 May 2023 10:45:43 -0700 Subject: [PATCH 043/196] A bit shorter stack. we can reverse this eventually when putting a trampoline in evaluate.rs --- src/compiler/comptypes.rs | 2 +- src/compiler/evaluate.rs | 6 +++--- src/compiler/inline.rs | 6 +++--- src/compiler/lambda.rs | 4 ++-- src/compiler/rename.rs | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 6e1105b0e..fb0e015fe 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -176,7 +176,7 @@ pub enum BodyForm { /// Captures are optional. /// The real args are given in the indicated shape when the lambda is applied /// with the 'a' operator. - Lambda(LambdaData), + Lambda(Box), } /// The information needed to know about a defun. Whether it's inline is left in diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index b32786d58..64a8e3474 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -695,7 +695,7 @@ impl<'info> Evaluator { )?; if let BodyForm::Lambda(ldata) = evaluated_prog.borrow() { return Ok(Some(LambdaApply { - lambda: ldata.clone(), + lambda: *ldata.clone(), body: ldata.body.clone(), env: evaluated_env, })); @@ -1088,10 +1088,10 @@ impl<'info> Evaluator { )?; // This is the first part of eta-conversion. - Ok(Rc::new(BodyForm::Lambda(LambdaData { + Ok(Rc::new(BodyForm::Lambda(Box::new(LambdaData { captures: new_captures, ..ldata.clone() - }))) + })))) } fn get_function(&self, name: &[u8]) -> Option> { diff --git a/src/compiler/inline.rs b/src/compiler/inline.rs index 70f703a1f..5102df54f 100644 --- a/src/compiler/inline.rs +++ b/src/compiler/inline.rs @@ -282,10 +282,10 @@ fn replace_inline_body( callsite, ldata.captures.clone(), )?; - Ok(Rc::new(BodyForm::Lambda(LambdaData { + Ok(Rc::new(BodyForm::Lambda(Box::new(LambdaData { captures: rewritten_captures, - ..ldata.clone() - }))) + ..*ldata.clone() + })))) } _ => Ok(expr.clone()), } diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index d84a3e550..bffc42da3 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -142,12 +142,12 @@ pub fn handle_lambda( // Requires captures let subparse = compile_bodyform(opts, Rc::new(v[1].clone()))?; - Ok(BodyForm::Lambda(LambdaData { + Ok(BodyForm::Lambda(Box::new(LambdaData { loc: v[0].loc(), kw: kw_loc, args: found.args.clone(), capture_args: found.capture_args.clone(), captures: found.captures, body: Rc::new(subparse), - })) + }))) } diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 9d3e991c3..172ddbb7d 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -175,12 +175,12 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B Rc::new(rename_in_bodyform(namemap, ldata.captures.clone())); let renamed_capture_outputs = rename_in_cons(namemap, ldata.capture_args.clone()); let renamed_body = rename_in_bodyform(namemap, ldata.body.clone()); - BodyForm::Lambda(LambdaData { + BodyForm::Lambda(Box::new(LambdaData { captures: renamed_capture_inputs, capture_args: renamed_capture_outputs, body: Rc::new(renamed_body), - ..ldata.clone() - }) + ..*ldata.clone() + })) } } } From 0aa7ad511b9e54e90c9697f0d5e1432f77dea2f1 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 23 May 2023 17:40:33 -0700 Subject: [PATCH 044/196] Start strict --- src/classic/clvm_tools/clvmc.rs | 29 ++++++++++++++++------------- src/classic/clvm_tools/cmds.rs | 6 +++--- src/compiler/compiler.rs | 12 +++++++++++- src/compiler/comptypes.rs | 11 +++++++++++ src/tests/classic/stage_2.rs | 8 +++++++- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index b2ac08bab..e18805338 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -22,10 +22,8 @@ use crate::classic::platform::distutils::dep_util::newer; use crate::compiler::clvm::convert_to_clvm_rs; use crate::compiler::compiler::compile_file; -use crate::compiler::compiler::run_optimizer; -use crate::compiler::compiler::DefaultCompilerOpts; -use crate::compiler::comptypes::CompileErr; -use crate::compiler::comptypes::CompilerOpts; +use crate::compiler::compiler::{DefaultCompilerOpts, run_optimizer}; +use crate::compiler::comptypes::{AcceptedDialect, CompileErr, CompilerOpts}; use crate::compiler::runtypes::RunFailure; fn include_dialect( @@ -56,15 +54,19 @@ pub fn write_sym_output( .map(|_| ()) } -pub fn detect_modern(allocator: &mut Allocator, sexp: NodePtr) -> Option { +pub fn detect_modern(allocator: &mut Allocator, sexp: NodePtr) -> AcceptedDialect { let mut dialects = HashMap::new(); dialects.insert("*standard-cl-21*".as_bytes().to_vec(), 21); dialects.insert("*standard-cl-22*".as_bytes().to_vec(), 22); - proper_list(allocator, sexp, true).and_then(|l| { + let mut result = Default::default(); + + if let Some(l) = proper_list(allocator, sexp, true) { for elt in l.iter() { - if let Some(dialect) = detect_modern(allocator, *elt) { - return Some(dialect); + let detect_modern_result = detect_modern(allocator, *elt); + if detect_modern_result.stepping.is_some() { + result = detect_modern_result; + break; } match proper_list(allocator, *elt, true) { @@ -78,14 +80,15 @@ pub fn detect_modern(allocator: &mut Allocator, sexp: NodePtr) -> Option { } if let Some(dialect) = include_dialect(allocator, &dialects, &e) { - return Some(dialect); + result.stepping = Some(dialect); + break; } } } } + } - None - }) + result } pub fn compile_clvm_text( @@ -98,8 +101,8 @@ pub fn compile_clvm_text( ) -> Result { let ir_src = read_ir(text).map_err(|s| EvalErr(allocator.null(), s.to_string()))?; let assembled_sexp = assemble_from_ir(allocator, Rc::new(ir_src))?; - - if let Some(dialect) = detect_modern(allocator, assembled_sexp) { + let dialect = detect_modern(allocator, assembled_sexp); + if let Some(dialect) = dialect.stepping { let runner = Rc::new(DefaultProgramRunner::new()); let opts = opts.set_optimize(true).set_frontend_opt(dialect > 21); diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 79eb746d7..dea8a5746 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -1145,9 +1145,9 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .map(|a| matches!(a, ArgumentValue::ArgBool(true))) .unwrap_or(false); - let dialect = input_sexp.and_then(|i| detect_modern(&mut allocator, i)); + let dialect = input_sexp.map(|i| detect_modern(&mut allocator, i)); let mut stderr_output = |s: String| { - if dialect.is_some() { + if dialect.as_ref().and_then(|d| d.stepping).is_some() { eprintln!("{s}"); } else { stdout.write_str(&s); @@ -1183,7 +1183,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .unwrap_or_else(|| "main.sym".to_string()); // In testing: short circuit for modern compilation. - if let Some(dialect) = dialect { + if let Some(dialect) = dialect.and_then(|d| d.stepping) { let do_optimize = parsed_args .get("optimize") .map(|x| matches!(x, ArgumentValue::ArgBool(true))) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 7639f88b5..0bab69b35 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -14,7 +14,7 @@ use crate::classic::clvm_tools::stages::stage_2::optimize::optimize_sexp; use crate::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, sha256tree}; use crate::compiler::codegen::{codegen, hoist_body_let_binding, process_helper_let_bindings}; use crate::compiler::comptypes::{ - CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, + AcceptedDialect, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, }; use crate::compiler::evaluate::{build_reflex_captures, Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::frontend::frontend; @@ -74,6 +74,7 @@ pub struct DefaultCompilerOpts { pub frontend_check_live: bool, pub start_env: Option>, pub prim_map: Rc, Rc>>, + pub dialect: AcceptedDialect, known_dialects: Rc>, } @@ -228,6 +229,9 @@ impl CompilerOpts for DefaultCompilerOpts { fn code_generator(&self) -> Option { self.code_generator.clone() } + fn dialect(&self) -> AcceptedDialect { + self.dialect.clone() + } fn in_defun(&self) -> bool { self.in_defun } @@ -253,6 +257,11 @@ impl CompilerOpts for DefaultCompilerOpts { self.include_dirs.clone() } + fn set_dialect(&self, dialect: AcceptedDialect) -> Rc { + let mut copy = self.clone(); + copy.dialect = dialect; + Rc::new(copy) + } fn set_search_paths(&self, dirs: &[String]) -> Rc { let mut copy = self.clone(); copy.include_dirs = dirs.to_owned(); @@ -349,6 +358,7 @@ impl DefaultCompilerOpts { frontend_opt: false, frontend_check_live: true, start_env: None, + dialect: Default::default(), prim_map: create_prim_map(), known_dialects: Rc::new(KNOWN_DIALECTS.clone()), } diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 0b7b89e1a..7febd5b2f 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -30,6 +30,13 @@ impl From<(Srcloc, String)> for CompileErr { #[derive(Clone, Debug)] pub struct CompiledCode(pub Srcloc, pub Rc); +/// Specifying how the language is spoken. +#[derive(Clone, Debug, Default)] +pub struct AcceptedDialect { + pub stepping: Option, + pub strict: bool, +} + /// A description of an inlined function for use during inline expansion. /// This is used only by PrimaryCodegen. #[derive(Clone, Debug)] @@ -309,6 +316,8 @@ pub trait CompilerOpts { /// complex constants, and into (com ...) forms. This allows the CompilerOpts /// to carry this info across boundaries into a new context. fn code_generator(&self) -> Option; + /// Get the dialect declared in the toplevel program. + fn dialect(&self) -> AcceptedDialect; /// Specifies whether code is being generated on behalf of an inner defun in /// the program. fn in_defun(&self) -> bool; @@ -333,6 +342,8 @@ pub trait CompilerOpts { /// Specifies the search paths we're carrying. fn get_search_paths(&self) -> Vec; + /// Set the dialect. + fn set_dialect(&self, dialect: AcceptedDialect) -> Rc; /// Set search paths. fn set_search_paths(&self, dirs: &[String]) -> Rc; /// Set whether we're compiling on behalf of a defun. diff --git a/src/tests/classic/stage_2.rs b/src/tests/classic/stage_2.rs index 0d80b005a..d7055c6d3 100644 --- a/src/tests/classic/stage_2.rs +++ b/src/tests/classic/stage_2.rs @@ -17,7 +17,7 @@ use crate::classic::clvm_tools::stages::stage_2::helpers::{brun, evaluate, quote use crate::classic::clvm_tools::stages::stage_2::operators::run_program_for_search_paths; use crate::classic::clvm_tools::stages::stage_2::reader::{process_embed_file, read_file}; -use crate::compiler::comptypes::{CompileErr, CompilerOpts, PrimaryCodegen}; +use crate::compiler::comptypes::{AcceptedDialect, CompileErr, CompilerOpts, PrimaryCodegen}; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; @@ -319,6 +319,9 @@ impl CompilerOpts for TestCompilerOptsPresentsOwnFiles { fn code_generator(&self) -> Option { None } + fn dialect(&self) -> AcceptedDialect { + Default::default() + } fn in_defun(&self) -> bool { false } @@ -343,6 +346,9 @@ impl CompilerOpts for TestCompilerOptsPresentsOwnFiles { fn get_search_paths(&self) -> Vec { vec![".".to_string()] } + fn set_dialect(&self, _dialect: AcceptedDialect) -> Rc { + Rc::new(self.clone()) + } fn set_search_paths(&self, _dirs: &[String]) -> Rc { Rc::new(self.clone()) } From f82fe4c1102244c0be5a2649224d64191a85183c Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 23 May 2023 16:50:26 -0700 Subject: [PATCH 045/196] fmt + clippy --- src/classic/clvm_tools/clvmc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index e18805338..0eeffed9f 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -22,7 +22,7 @@ use crate::classic::platform::distutils::dep_util::newer; use crate::compiler::clvm::convert_to_clvm_rs; use crate::compiler::compiler::compile_file; -use crate::compiler::compiler::{DefaultCompilerOpts, run_optimizer}; +use crate::compiler::compiler::{run_optimizer, DefaultCompilerOpts}; use crate::compiler::comptypes::{AcceptedDialect, CompileErr, CompilerOpts}; use crate::compiler::runtypes::RunFailure; From ca4e65a7985733ff52183c2c32113288fcd8ba27 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 25 May 2023 17:29:02 -0700 Subject: [PATCH 046/196] Merge up the easy parts --- resources/tests/strict/strict-list-fail.clsp | 4 + resources/tests/strict/strict-list-pass.clsp | 4 + resources/tests/strict/strict-test-fail.clsp | 9 ++ resources/tests/strict/strict-test-pass.clsp | 7 ++ src/classic/clvm_tools/clvmc.rs | 68 ++--------- src/classic/clvm_tools/cmds.rs | 15 ++- src/compiler/codegen.rs | 44 ++++--- src/compiler/compiler.rs | 62 ++++++---- src/compiler/comptypes.rs | 56 ++++++--- src/compiler/dialect.rs | 119 +++++++++++++++++++ src/compiler/frontend.rs | 2 + src/compiler/mod.rs | 3 +- src/compiler/preprocessor/mod.rs | 7 +- src/compiler/rename.rs | 12 +- src/tests/classic/run.rs | 108 +++++++++++++++++ src/tests/classic/stage_2.rs | 3 +- 16 files changed, 391 insertions(+), 132 deletions(-) create mode 100644 resources/tests/strict/strict-list-fail.clsp create mode 100644 resources/tests/strict/strict-list-pass.clsp create mode 100644 resources/tests/strict/strict-test-fail.clsp create mode 100644 resources/tests/strict/strict-test-pass.clsp create mode 100644 src/compiler/dialect.rs diff --git a/resources/tests/strict/strict-list-fail.clsp b/resources/tests/strict/strict-list-fail.clsp new file mode 100644 index 000000000..9e4e42502 --- /dev/null +++ b/resources/tests/strict/strict-list-fail.clsp @@ -0,0 +1,4 @@ +(mod (X) + (include *strict-cl-21*) + (list X (+ X 1) (+ X2)) + ) diff --git a/resources/tests/strict/strict-list-pass.clsp b/resources/tests/strict/strict-list-pass.clsp new file mode 100644 index 000000000..efbba4770 --- /dev/null +++ b/resources/tests/strict/strict-list-pass.clsp @@ -0,0 +1,4 @@ +(mod (X) + (include *strict-cl-21*) + (list X (+ X 1) (+ X 2)) + ) diff --git a/resources/tests/strict/strict-test-fail.clsp b/resources/tests/strict/strict-test-fail.clsp new file mode 100644 index 000000000..4ca88390b --- /dev/null +++ b/resources/tests/strict/strict-test-fail.clsp @@ -0,0 +1,9 @@ +(mod (X) + (include *strict-cl-21*) + ;; This wouldn't be able to be rejected because X1 is coming from a macro + ;; expansion. This should fail in strict but succeed wrong non-strict. + (if X + (+ X1 2) + 5 + ) + ) diff --git a/resources/tests/strict/strict-test-pass.clsp b/resources/tests/strict/strict-test-pass.clsp new file mode 100644 index 000000000..6dfbc39de --- /dev/null +++ b/resources/tests/strict/strict-test-pass.clsp @@ -0,0 +1,7 @@ +(mod (X) + (include *strict-cl-21*) + (if X + (+ X 2) + 5 + ) + ) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index 0eeffed9f..f8ae6a6bc 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -6,12 +6,11 @@ use std::rc::Rc; use tempfile::NamedTempFile; -use clvm_rs::allocator::{Allocator, NodePtr, SExp}; +use clvm_rs::allocator::{Allocator, NodePtr}; use clvm_rs::reduction::EvalErr; use crate::classic::clvm::__type_compatibility__::Stream; use crate::classic::clvm::serialize::sexp_to_stream; -use crate::classic::clvm::sexp::proper_list; use crate::classic::clvm_tools::binutils::{assemble_from_ir, disassemble}; use crate::classic::clvm_tools::ir::reader::read_ir; use crate::classic::clvm_tools::stages::run; @@ -23,25 +22,10 @@ use crate::classic::platform::distutils::dep_util::newer; use crate::compiler::clvm::convert_to_clvm_rs; use crate::compiler::compiler::compile_file; use crate::compiler::compiler::{run_optimizer, DefaultCompilerOpts}; -use crate::compiler::comptypes::{AcceptedDialect, CompileErr, CompilerOpts}; +use crate::compiler::comptypes::{CompileErr, CompilerOpts}; +use crate::compiler::dialect::detect_modern; use crate::compiler::runtypes::RunFailure; -fn include_dialect( - allocator: &mut Allocator, - dialects: &HashMap, i32>, - e: &[NodePtr], -) -> Option { - if let (SExp::Atom(inc), SExp::Atom(name)) = (allocator.sexp(e[0]), allocator.sexp(e[1])) { - if allocator.buf(&inc) == "include".as_bytes().to_vec() { - if let Some(dialect) = dialects.get(allocator.buf(&name)) { - return Some(*dialect); - } - } - } - - None -} - pub fn write_sym_output( compiled_lookup: &HashMap, path: &str, @@ -54,44 +38,7 @@ pub fn write_sym_output( .map(|_| ()) } -pub fn detect_modern(allocator: &mut Allocator, sexp: NodePtr) -> AcceptedDialect { - let mut dialects = HashMap::new(); - dialects.insert("*standard-cl-21*".as_bytes().to_vec(), 21); - dialects.insert("*standard-cl-22*".as_bytes().to_vec(), 22); - - let mut result = Default::default(); - - if let Some(l) = proper_list(allocator, sexp, true) { - for elt in l.iter() { - let detect_modern_result = detect_modern(allocator, *elt); - if detect_modern_result.stepping.is_some() { - result = detect_modern_result; - break; - } - - match proper_list(allocator, *elt, true) { - None => { - continue; - } - - Some(e) => { - if e.len() != 2 { - continue; - } - - if let Some(dialect) = include_dialect(allocator, &dialects, &e) { - result.stepping = Some(dialect); - break; - } - } - } - } - } - - result -} - -pub fn compile_clvm_text( +pub fn compile_clvm_text_maybe_opt( allocator: &mut Allocator, opts: Rc, symbol_table: &mut HashMap, @@ -102,9 +49,12 @@ pub fn compile_clvm_text( let ir_src = read_ir(text).map_err(|s| EvalErr(allocator.null(), s.to_string()))?; let assembled_sexp = assemble_from_ir(allocator, Rc::new(ir_src))?; let dialect = detect_modern(allocator, assembled_sexp); - if let Some(dialect) = dialect.stepping { + if let Some(stepping) = dialect.stepping { let runner = Rc::new(DefaultProgramRunner::new()); - let opts = opts.set_optimize(true).set_frontend_opt(dialect > 21); + let opts = opts + .set_dialect(dialect) + .set_optimize(do_optimize) + .set_frontend_opt(stepping > 21); let unopt_res = compile_file(allocator, runner.clone(), opts, text, symbol_table); let res = unopt_res.and_then(|x| run_optimizer(allocator, runner, Rc::new(x))); diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index dea8a5746..7238d0de1 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -27,7 +27,7 @@ use crate::classic::clvm::keyword_from_atom; use crate::classic::clvm::serialize::{sexp_from_stream, sexp_to_stream, SimpleCreateCLVMObject}; use crate::classic::clvm::sexp::{enlist, proper_list, sexp_as_bin}; use crate::classic::clvm_tools::binutils::{assemble_from_ir, disassemble, disassemble_with_kw}; -use crate::classic::clvm_tools::clvmc::{detect_modern, write_sym_output}; +use crate::classic::clvm_tools::clvmc::write_sym_output; use crate::classic::clvm_tools::debug::check_unused; use crate::classic::clvm_tools::debug::{ program_hash_from_program_env_cons, start_log_after, trace_pre_eval, trace_to_table, @@ -53,6 +53,8 @@ use crate::compiler::clvm::start_step; use crate::compiler::compiler::{compile_file, run_optimizer, DefaultCompilerOpts}; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::debug::build_symbol_table_mut; +use crate::compiler::dialect::detect_modern; +use crate::compiler::frontend::frontend; use crate::compiler::preprocessor::gather_dependencies; use crate::compiler::prims; use crate::compiler::runtypes::RunFailure; @@ -910,6 +912,12 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .set_type(Rc::new(PathJoin {})) .set_default(ArgumentValue::ArgString(None, "main.sym".to_string())), ); + parser.add_argument( + vec!["--strict".to_string()], + Argument::new() + .set_action(TArgOptionAction::StoreTrue) + .set_help("For modern dialects, don't treat unknown names as constants".to_string()), + ); if tool_name == "run" { parser.add_argument( @@ -1183,7 +1191,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .unwrap_or_else(|| "main.sym".to_string()); // In testing: short circuit for modern compilation. - if let Some(dialect) = dialect.and_then(|d| d.stepping) { + if let Some(stepping) = dialect.as_ref().and_then(|d| d.stepping) { let do_optimize = parsed_args .get("optimize") .map(|x| matches!(x, ArgumentValue::ArgBool(true))) @@ -1191,9 +1199,10 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let runner = Rc::new(DefaultProgramRunner::new()); let use_filename = input_file.unwrap_or_else(|| "*command*".to_string()); let opts = Rc::new(DefaultCompilerOpts::new(&use_filename)) + .set_dialect(dialect.unwrap_or_else(|| Default::default())) .set_optimize(do_optimize) .set_search_paths(&search_paths) - .set_frontend_opt(dialect > 21); + .set_frontend_opt(stepping > 21); let mut symbol_table = HashMap::new(); let unopt_res = compile_file( diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 20fff0062..55de7d0e0 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -526,6 +526,10 @@ pub fn generate_expr_code( create_name_lookup(compiler, l.clone(), atom) .map(|f| Ok(CompiledCode(l.clone(), f))) .unwrap_or_else(|_| { + if opts.dialect().strict { + return Err(CompileErr(l.clone(), format!("Unbound use of {} as a variable name", decode_string(atom)))); + } + // Pass through atoms that don't look up on behalf of // macros, as it's possible that a macro returned // something that's canonically a name in number form. @@ -539,20 +543,32 @@ pub fn generate_expr_code( }) } } - // Since macros are in this language and the runtime has - // a very narrow data representation, we'll need to - // accomodate bare numbers coming back in place of identifiers. - // I'm considering ways to make this better. - SExp::Integer(l, i) => generate_expr_code( - allocator, - runner, - opts, - compiler, - Rc::new(BodyForm::Value(SExp::Atom( - l.clone(), - u8_from_number(i.clone()), - ))), - ), + SExp::Integer(l, i) => { + if opts.dialect().strict { + return generate_expr_code( + allocator, + runner, + opts, + compiler, + Rc::new(BodyForm::Quoted(SExp::Integer(l.clone(), i.clone()))), + ); + } + + // Since macros are in this language and the runtime has + // a very narrow data representation, we'll need to + // accomodate bare numbers coming back in place of identifiers, + // but only in legacy non-strict mode. + generate_expr_code( + allocator, + runner, + opts, + compiler, + Rc::new(BodyForm::Value(SExp::Atom( + l.clone(), + u8_from_number(i.clone()), + ))), + ) + } _ => Ok(CompiledCode( v.loc(), Rc::new(primquote(v.loc(), Rc::new(v.clone()))), diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 0bab69b35..13114ce0a 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -14,8 +14,9 @@ use crate::classic::clvm_tools::stages::stage_2::optimize::optimize_sexp; use crate::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, sha256tree}; use crate::compiler::codegen::{codegen, hoist_body_let_binding, process_helper_let_bindings}; use crate::compiler::comptypes::{ - AcceptedDialect, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, + CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, }; +use crate::compiler::dialect::{AcceptedDialect, KNOWN_DIALECTS}; use crate::compiler::evaluate::{build_reflex_captures, Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::frontend::frontend; use crate::compiler::prims; @@ -25,24 +26,6 @@ use crate::compiler::srcloc::Srcloc; use crate::util::Number; lazy_static! { - pub static ref KNOWN_DIALECTS: HashMap = { - let mut known_dialects: HashMap = HashMap::new(); - known_dialects.insert( - "*standard-cl-21*".to_string(), - indoc! {"( - (defconstant *chialisp-version* 21) - )"} - .to_string(), - ); - known_dialects.insert( - "*standard-cl-22*".to_string(), - indoc! {"( - (defconstant *chialisp-version* 22) - )"} - .to_string(), - ); - known_dialects - }; pub static ref STANDARD_MACROS: String = { indoc! {"( (defmacro if (A B C) (qq (a (i (unquote A) (com (unquote B)) (com (unquote C))) @))) @@ -60,6 +43,34 @@ lazy_static! { "} .to_string() }; + + pub static ref ADVANCED_MACROS: String = { + indoc! {"( + (defmac if (A B C) + (qq (a (i (unquote A) (com (unquote B)) (com (unquote C))) @)) + ) + + (defun __chia__compile-list (args) + (if args + (c 4 (c (f args) (c (__chia__compile-list (r args)) ()))) + () + ) + ) + + (defmac list ARGS (__chia__compile-list ARGS)) + + (defun-inline / (A B) (f (divmod A B))) + (defun-inline c* (A B) (c A B)) + (defun-inline a* (A B) (a A B)) + (defun-inline coerce (X) : (Any -> Any) X) + (defun-inline explode (X) : (forall a ((Exec a) -> a)) X) + (defun-inline bless (X) : (forall a ((Pair a Unit) -> (Exec a))) (coerce X)) + (defun-inline lift (X V) : (forall a (forall b ((Pair (Exec a) (Pair b Unit)) -> (Exec (Pair a b))))) (coerce X)) + (defun-inline unlift (X) : (forall a (forall b ((Pair (Exec (Pair a b)) Unit) -> (Exec b)))) (coerce X)) + ) + "} + .to_string() + }; } #[derive(Clone, Debug)] @@ -75,8 +86,6 @@ pub struct DefaultCompilerOpts { pub start_env: Option>, pub prim_map: Rc, Rc>>, pub dialect: AcceptedDialect, - - known_dialects: Rc>, } pub fn create_prim_map() -> Rc, Rc>> { @@ -309,9 +318,13 @@ impl CompilerOpts for DefaultCompilerOpts { filename: String, ) -> Result<(String, String), CompileErr> { if filename == "*macros*" { - return Ok((filename, STANDARD_MACROS.clone())); - } else if let Some(content) = self.known_dialects.get(&filename) { - return Ok((filename, content.to_string())); + if self.dialect().strict { + return Ok((filename, ADVANCED_MACROS.clone().as_bytes().to_vec())); + } else { + return Ok((filename, STANDARD_MACROS.clone().as_bytes().to_vec())); + } + } else if let Some(dialect) = KNOWN_DIALECTS.get(&filename) { + return Ok((filename, dialect.content.as_bytes().to_vec())); } for dir in self.include_dirs.iter() { @@ -360,7 +373,6 @@ impl DefaultCompilerOpts { start_env: None, dialect: Default::default(), prim_map: create_prim_map(), - known_dialects: Rc::new(KNOWN_DIALECTS.clone()), } } } diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 7febd5b2f..1fe5b8eef 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -9,8 +9,9 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{Bytes, BytesFromType}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::sha256tree; -use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::clvm::{sha256tree, truthy}; +use crate::compiler::dialect::AcceptedDialect; +use crate::compiler::sexp::{decode_string, enlist, SExp}; use crate::compiler::srcloc::Srcloc; /// The basic error type. It contains a Srcloc identifying coordinates of the @@ -30,13 +31,6 @@ impl From<(Srcloc, String)> for CompileErr { #[derive(Clone, Debug)] pub struct CompiledCode(pub Srcloc, pub Rc); -/// Specifying how the language is spoken. -#[derive(Clone, Debug, Default)] -pub struct AcceptedDialect { - pub stepping: Option, - pub strict: bool, -} - /// A description of an inlined function for use during inline expansion. /// This is used only by PrimaryCodegen. #[derive(Clone, Debug)] @@ -192,6 +186,8 @@ pub struct DefmacData { pub args: Rc, /// The program appearing in the macro definition. pub program: Rc, + /// Whether this is an an advanced macro. + pub advanced: bool } /// Information from a constant definition. @@ -494,6 +490,38 @@ impl CompileForm { } } +pub fn generate_defmacro_sexp(mac: &DefmacData) -> Rc { + if mac.advanced { + Rc::new(SExp::Cons( + mac.loc.clone(), + Rc::new(SExp::atom_from_string(mac.loc.clone(), "defmac")), + Rc::new(SExp::Cons( + mac.loc.clone(), + Rc::new(SExp::atom_from_vec(mac.nl.clone(), &mac.name)), + Rc::new(SExp::Cons( + mac.loc.clone(), + mac.args.clone(), + Rc::new(SExp::Cons( + mac.loc.clone(), + mac.program.exp.to_sexp(), + Rc::new(SExp::Nil(mac.loc.clone())) + )), + )), + )), + )) + } else { + Rc::new(SExp::Cons( + mac.loc.clone(), + Rc::new(SExp::atom_from_string(mac.loc.clone(), "defmacro")), + Rc::new(SExp::Cons( + mac.loc.clone(), + Rc::new(SExp::atom_from_vec(mac.nl.clone(), &mac.name)), + mac.program.to_sexp(), + )), + )) + } +} + impl HelperForm { /// Get a reference to the HelperForm's name. pub fn name(&self) -> &Vec { @@ -544,15 +572,7 @@ impl HelperForm { ], )), }, - HelperForm::Defmacro(mac) => Rc::new(SExp::Cons( - mac.loc.clone(), - Rc::new(SExp::atom_from_string(mac.loc.clone(), "defmacro")), - Rc::new(SExp::Cons( - mac.loc.clone(), - Rc::new(SExp::atom_from_vec(mac.nl.clone(), &mac.name)), - mac.program.to_sexp(), - )), - )), + HelperForm::Defmacro(mac) => generate_defmacro_sexp(&mac), HelperForm::Defun(inline, defun) => { let di_string = "defun-inline".to_string(); let d_string = "defun".to_string(); diff --git a/src/compiler/dialect.rs b/src/compiler/dialect.rs new file mode 100644 index 000000000..c5b533d87 --- /dev/null +++ b/src/compiler/dialect.rs @@ -0,0 +1,119 @@ +use std::collections::HashMap; + +use clvmr::allocator::{Allocator, NodePtr, SExp}; + +use crate::classic::clvm::sexp::proper_list; + +use crate::compiler::sexp::decode_string; + +/// Specifying how the language is spoken. +#[derive(Clone, Debug, Default)] +pub struct AcceptedDialect { + pub stepping: Option, + pub strict: bool, +} + +/// A package containing the content we should insert when a dialect include is +/// used, plus the compilation flags. +#[derive(Clone, Debug)] +pub struct DialectDescription { + pub accepted: AcceptedDialect, + pub content: String +} + +lazy_static! { + pub static ref KNOWN_DIALECTS: HashMap = { + let mut dialects: HashMap = HashMap::new(); + let dialect_list = [ + ("*standard-cl-21*", DialectDescription { + accepted: AcceptedDialect { + stepping: Some(21), + .. Default::default() + }, + content: indoc! {"( + (defconstant *chialisp-version* 21) + )"}.to_string() + }), + ("*strict-cl-21*", DialectDescription { + accepted: AcceptedDialect { + stepping: Some(21), + strict: true + }, + content: indoc! {"( + (defconstant *chialisp-version* 22) + )"}.to_string() + }), + ("*standard-cl-22*", DialectDescription { + accepted: AcceptedDialect { + stepping: Some(22), + strict: false + }, + content: indoc! {"( + (defconstant *chialisp-version* 22) + )"}.to_string() + }), + ("*standard-cl-23*", DialectDescription { + accepted: AcceptedDialect { + stepping: Some(23), + strict: true + }, + content: indoc! {"( + (defconstant *chialisp-version* 23) + )"}.to_string() + }), + ]; + for (n,v) in dialect_list.iter() { + dialects.insert(n.to_string(), v.clone()); + } + dialects + }; +} + +fn include_dialect( + allocator: &mut Allocator, + e: &[NodePtr], +) -> Option +{ + if let (SExp::Atom(inc), SExp::Atom(name)) = (allocator.sexp(e[0]), allocator.sexp(e[1])) { + if allocator.buf(&inc) == "include".as_bytes().to_vec() { + if let Some(dialect) = KNOWN_DIALECTS.get(&decode_string(&allocator.buf(&name))) { + return Some(dialect.accepted.clone()); + } + } + } + + None +} + +pub fn detect_modern(allocator: &mut Allocator, sexp: NodePtr) -> AcceptedDialect { + let mut result = Default::default(); + + if let Some(l) = proper_list(allocator, sexp, true) { + for elt in l.iter() { + let detect_modern_result = detect_modern(allocator, *elt); + if detect_modern_result.stepping.is_some() { + result = detect_modern_result; + break; + } + + match proper_list(allocator, *elt, true) { + None => { + continue; + } + + Some(e) => { + if e.len() != 2 { + continue; + } + + if let Some(dialect) = include_dialect(allocator, &e) { + result = dialect; + break; + } + } + } + } + } + + result +} diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index b493d4559..f552147fd 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -478,6 +478,7 @@ fn compile_defmacro( name, args: args.clone(), program: Rc::new(p), + advanced: false, }) }) } @@ -695,6 +696,7 @@ fn frontend_start( )) } else { let l = pre_forms[0].loc(); + eprintln!("pre_forms {}", pre_forms[0]); pre_forms[0] .proper_list() .map(|x| { diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 32e12ad78..e37a2f70d 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -13,8 +13,9 @@ pub mod compiler; /// - CompileForm - The type of finished (mod ) forms before code generation. /// - HelperForm - The type of declarations like macros, constants and functions. pub mod comptypes; -/// pub mod debug; +/// Dialect definitions. +pub mod dialect; pub mod evaluate; pub mod frontend; pub mod gensym; diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 77d77d94d..aa4fd6595 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -8,8 +8,11 @@ use clvmr::allocator::Allocator; use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; -use crate::compiler::compiler::KNOWN_DIALECTS; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc}; +use crate::compiler::cldb::hex_to_modern_sexp; +use crate::compiler::dialect::KNOWN_DIALECTS; +use crate::compiler::comptypes::{ + BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc, +}; use crate::compiler::evaluate::{create_argument_captures, dequote, ArgInputs, Evaluator}; use crate::compiler::frontend::compile_helperform; use crate::compiler::preprocessor::macros::PreprocessorExtension; diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 9b2e42ed5..81a1d8b23 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -271,12 +271,9 @@ fn rename_in_helperform(namemap: &HashMap, Vec>, h: &HelperForm) -> body: Rc::new(rename_in_bodyform(namemap, defc.body.clone())), }), HelperForm::Defmacro(mac) => HelperForm::Defmacro(DefmacData { - loc: mac.loc.clone(), - kw: mac.kw.clone(), - nl: mac.nl.clone(), - name: mac.name.to_vec(), - args: mac.args.clone(), program: Rc::new(rename_in_compileform(namemap, mac.program.clone())), + ..mac.clone() + }), HelperForm::Defun(inline, defun) => HelperForm::Defun( *inline, @@ -315,15 +312,12 @@ fn rename_args_helperform(h: &HelperForm) -> HelperForm { let local_renamed_arg = rename_in_cons(&local_namemap, mac.args.clone()); let local_renamed_body = rename_args_compileform(mac.program.borrow()); HelperForm::Defmacro(DefmacData { - loc: mac.loc.clone(), - kw: mac.kw.clone(), - nl: mac.nl.clone(), - name: mac.name.clone(), args: local_renamed_arg, program: Rc::new(rename_in_compileform( &local_namemap, Rc::new(local_renamed_body), )), + .. mac.clone() }) } HelperForm::Defun(inline, defun) => { diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 6a849743a..0fb736ec0 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -869,3 +869,111 @@ fn test_cost_reporting_0() { "cost = 1978\n0x6fcb06b1fe29d132bb37f3a21b86d7cf03d636bf6230aa206486bef5e68f9875" ); } + +#[test] +fn test_assign_lambda_code_generation() { + let tname = "test_assign_lambda_code_generation.sym".to_string(); + do_basic_run(&vec![ + "run".to_string(), + "--extra-syms".to_string(), + "--symbol-output-file".to_string(), + tname.clone(), + "(mod (A) (include *standard-cl-21*) (defun F (X) (+ X 1)) (assign-lambda X (F A) X))" + .to_string(), + ]); + let read_in_file = fs::read_to_string(&tname).expect("should have dropped symbols"); + fs::remove_file(&tname).expect("should have existed"); + let decoded_symbol_file: HashMap = + serde_json::from_str(&read_in_file).expect("should decode"); + let found_wanted_symbols: Vec = decoded_symbol_file + .iter() + .filter(|(_, v)| *v == "F" || v.starts_with("letbinding")) + .map(|(k, _)| k.clone()) + .collect(); + assert_eq!(found_wanted_symbols.len(), 2); + // We should have these two functions. + assert!(found_wanted_symbols + .contains(&"ccd5be506752cebf01f9930b4c108fe18058c65e1ab57a72ca0a00d9788c7ca6".to_string())); + assert!(found_wanted_symbols + .contains(&"0a5af5ae61fae2e53cb309d4d9c2c64baf0261824823008b9cf2b21b09221e44".to_string())); +} + +#[test] +fn test_assign_lambda_code_generation_inline() { + let tname = "test_assign_inline_code_generation.sym".to_string(); + do_basic_run(&vec![ + "run".to_string(), + "--extra-syms".to_string(), + "--symbol-output-file".to_string(), + tname.clone(), + "(mod (A) (include *standard-cl-21*) (defun F (X) (+ X 1)) (assign-inline X (F A) X))" + .to_string(), + ]); + let read_in_file = fs::read_to_string(&tname).expect("should have dropped symbols"); + fs::remove_file(&tname).expect("should have existed"); + let decoded_symbol_file: HashMap = + serde_json::from_str(&read_in_file).expect("should decode"); + let found_wanted_symbols: Vec = decoded_symbol_file + .iter() + .filter(|(_, v)| *v == "F" || v.starts_with("letbinding")) + .map(|(k, _)| k.clone()) + .collect(); + assert_eq!(found_wanted_symbols.len(), 1); + // We should have these two functions. + assert!(found_wanted_symbols + .contains(&"ccd5be506752cebf01f9930b4c108fe18058c65e1ab57a72ca0a00d9788c7ca6".to_string())); +} + +#[test] +fn test_assign_fancy_final_dot_rest() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/chia-gaming".to_string(), + "resources/tests/chia-gaming/test-last.clsp".to_string(), + ]); + let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "()".to_string()]) + .trim() + .to_string(); + assert_eq!(result, "101"); +} + +#[test] +fn test_strict_smoke_0() { + let result = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/strict-test-fail.clsp".to_string(), + ]); + assert!(result.contains("Unbound")); + assert!(result.contains("X1")); +} + +#[test] +fn test_strict_smoke_1() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/strict-test-pass.clsp".to_string(), + ]); + let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "(13)".to_string()]) + .trim() + .to_string(); + assert_eq!(result, "15"); +} + +/* +#[test] +fn test_strict_list_fail() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/strict-list-fail.clsp".to_string(), + ]); + eprintln!("result_prog {result_prog}"); + todo!(); +} +*/ diff --git a/src/tests/classic/stage_2.rs b/src/tests/classic/stage_2.rs index d7055c6d3..a83846b9f 100644 --- a/src/tests/classic/stage_2.rs +++ b/src/tests/classic/stage_2.rs @@ -17,7 +17,8 @@ use crate::classic::clvm_tools::stages::stage_2::helpers::{brun, evaluate, quote use crate::classic::clvm_tools::stages::stage_2::operators::run_program_for_search_paths; use crate::classic::clvm_tools::stages::stage_2::reader::{process_embed_file, read_file}; -use crate::compiler::comptypes::{AcceptedDialect, CompileErr, CompilerOpts, PrimaryCodegen}; +use crate::compiler::comptypes::{CompileErr, CompilerOpts, PrimaryCodegen}; +use crate::compiler::dialect::AcceptedDialect; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; From 7341d4085f7be51d0f7fee304c3f5f9986449e22 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 29 May 2023 16:13:00 -0700 Subject: [PATCH 047/196] fmt + clippy --- src/classic/clvm_tools/clvmc.rs | 20 ++++++++ src/classic/clvm_tools/cmds.rs | 3 +- src/compiler/codegen.rs | 8 ++- src/compiler/compiler.rs | 7 ++- src/compiler/comptypes.rs | 10 ++-- src/compiler/dialect.rs | 86 ++++++++++++++++++-------------- src/compiler/frontend.rs | 1 - src/compiler/preprocessor/mod.rs | 5 +- src/compiler/rename.rs | 3 +- src/tests/classic/run.rs | 68 ------------------------- 10 files changed, 87 insertions(+), 124 deletions(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index f8ae6a6bc..73e40050e 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -40,6 +40,7 @@ pub fn write_sym_output( pub fn compile_clvm_text_maybe_opt( allocator: &mut Allocator, + do_optimize: bool, opts: Rc, symbol_table: &mut HashMap, text: &str, @@ -79,6 +80,25 @@ pub fn compile_clvm_text_maybe_opt( } } +pub fn compile_clvm_text( + allocator: &mut Allocator, + opts: Rc, + symbol_table: &mut HashMap, + text: &str, + input_path: &str, + classic_with_opts: bool, +) -> Result { + compile_clvm_text_maybe_opt( + allocator, + true, + opts, + symbol_table, + text, + input_path, + classic_with_opts, + ) +} + pub fn compile_clvm_inner( allocator: &mut Allocator, opts: Rc, diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 7238d0de1..f8c2d7549 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -54,7 +54,6 @@ use crate::compiler::compiler::{compile_file, run_optimizer, DefaultCompilerOpts use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::debug::build_symbol_table_mut; use crate::compiler::dialect::detect_modern; -use crate::compiler::frontend::frontend; use crate::compiler::preprocessor::gather_dependencies; use crate::compiler::prims; use crate::compiler::runtypes::RunFailure; @@ -1199,7 +1198,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let runner = Rc::new(DefaultProgramRunner::new()); let use_filename = input_file.unwrap_or_else(|| "*command*".to_string()); let opts = Rc::new(DefaultCompilerOpts::new(&use_filename)) - .set_dialect(dialect.unwrap_or_else(|| Default::default())) + .set_dialect(dialect.unwrap_or_default()) .set_optimize(do_optimize) .set_search_paths(&search_paths) .set_frontend_opt(stepping > 21); diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 55de7d0e0..064512485 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -527,7 +527,13 @@ pub fn generate_expr_code( .map(|f| Ok(CompiledCode(l.clone(), f))) .unwrap_or_else(|_| { if opts.dialect().strict { - return Err(CompileErr(l.clone(), format!("Unbound use of {} as a variable name", decode_string(atom)))); + return Err(CompileErr( + l.clone(), + format!( + "Unbound use of {} as a variable name", + decode_string(atom) + ), + )); } // Pass through atoms that don't look up on behalf of diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 13114ce0a..ec9577096 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -43,7 +43,6 @@ lazy_static! { "} .to_string() }; - pub static ref ADVANCED_MACROS: String = { indoc! {"( (defmac if (A B C) @@ -319,12 +318,12 @@ impl CompilerOpts for DefaultCompilerOpts { ) -> Result<(String, String), CompileErr> { if filename == "*macros*" { if self.dialect().strict { - return Ok((filename, ADVANCED_MACROS.clone().as_bytes().to_vec())); + return Ok((filename, ADVANCED_MACROS.clone())); } else { - return Ok((filename, STANDARD_MACROS.clone().as_bytes().to_vec())); + return Ok((filename, STANDARD_MACROS.clone())); } } else if let Some(dialect) = KNOWN_DIALECTS.get(&filename) { - return Ok((filename, dialect.content.as_bytes().to_vec())); + return Ok((filename, dialect.content.clone())); } for dir in self.include_dirs.iter() { diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 1fe5b8eef..500590e74 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -9,9 +9,9 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{Bytes, BytesFromType}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::{sha256tree, truthy}; +use crate::compiler::clvm::sha256tree; use crate::compiler::dialect::AcceptedDialect; -use crate::compiler::sexp::{decode_string, enlist, SExp}; +use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; /// The basic error type. It contains a Srcloc identifying coordinates of the @@ -187,7 +187,7 @@ pub struct DefmacData { /// The program appearing in the macro definition. pub program: Rc, /// Whether this is an an advanced macro. - pub advanced: bool + pub advanced: bool, } /// Information from a constant definition. @@ -504,7 +504,7 @@ pub fn generate_defmacro_sexp(mac: &DefmacData) -> Rc { Rc::new(SExp::Cons( mac.loc.clone(), mac.program.exp.to_sexp(), - Rc::new(SExp::Nil(mac.loc.clone())) + Rc::new(SExp::Nil(mac.loc.clone())), )), )), )), @@ -572,7 +572,7 @@ impl HelperForm { ], )), }, - HelperForm::Defmacro(mac) => generate_defmacro_sexp(&mac), + HelperForm::Defmacro(mac) => generate_defmacro_sexp(mac), HelperForm::Defun(inline, defun) => { let di_string = "defun-inline".to_string(); let d_string = "defun".to_string(); diff --git a/src/compiler/dialect.rs b/src/compiler/dialect.rs index c5b533d87..062cb47c2 100644 --- a/src/compiler/dialect.rs +++ b/src/compiler/dialect.rs @@ -18,65 +18,77 @@ pub struct AcceptedDialect { #[derive(Clone, Debug)] pub struct DialectDescription { pub accepted: AcceptedDialect, - pub content: String + pub content: String, } lazy_static! { pub static ref KNOWN_DIALECTS: HashMap = { let mut dialects: HashMap = HashMap::new(); let dialect_list = [ - ("*standard-cl-21*", DialectDescription { - accepted: AcceptedDialect { - stepping: Some(21), - .. Default::default() - }, - content: indoc! {"( + ( + "*standard-cl-21*", + DialectDescription { + accepted: AcceptedDialect { + stepping: Some(21), + ..Default::default() + }, + content: indoc! {"( (defconstant *chialisp-version* 21) - )"}.to_string() - }), - ("*strict-cl-21*", DialectDescription { - accepted: AcceptedDialect { - stepping: Some(21), - strict: true + )"} + .to_string(), }, - content: indoc! {"( + ), + ( + "*strict-cl-21*", + DialectDescription { + accepted: AcceptedDialect { + stepping: Some(21), + strict: true, + }, + content: indoc! {"( (defconstant *chialisp-version* 22) - )"}.to_string() - }), - ("*standard-cl-22*", DialectDescription { - accepted: AcceptedDialect { - stepping: Some(22), - strict: false + )"} + .to_string(), }, - content: indoc! {"( + ), + ( + "*standard-cl-22*", + DialectDescription { + accepted: AcceptedDialect { + stepping: Some(22), + strict: false, + }, + content: indoc! {"( (defconstant *chialisp-version* 22) - )"}.to_string() - }), - ("*standard-cl-23*", DialectDescription { - accepted: AcceptedDialect { - stepping: Some(23), - strict: true + )"} + .to_string(), }, - content: indoc! {"( + ), + ( + "*standard-cl-23*", + DialectDescription { + accepted: AcceptedDialect { + stepping: Some(23), + strict: true, + }, + content: indoc! {"( (defconstant *chialisp-version* 23) - )"}.to_string() - }), + )"} + .to_string(), + }, + ), ]; - for (n,v) in dialect_list.iter() { + for (n, v) in dialect_list.iter() { dialects.insert(n.to_string(), v.clone()); } dialects }; } -fn include_dialect( - allocator: &mut Allocator, - e: &[NodePtr], -) -> Option -{ +fn include_dialect(allocator: &mut Allocator, e: &[NodePtr]) -> Option { if let (SExp::Atom(inc), SExp::Atom(name)) = (allocator.sexp(e[0]), allocator.sexp(e[1])) { if allocator.buf(&inc) == "include".as_bytes().to_vec() { - if let Some(dialect) = KNOWN_DIALECTS.get(&decode_string(&allocator.buf(&name))) { + if let Some(dialect) = KNOWN_DIALECTS.get(&decode_string(allocator.buf(&name))) { return Some(dialect.accepted.clone()); } } diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index f552147fd..c4f6b80dd 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -696,7 +696,6 @@ fn frontend_start( )) } else { let l = pre_forms[0].loc(); - eprintln!("pre_forms {}", pre_forms[0]); pre_forms[0] .proper_list() .map(|x| { diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index aa4fd6595..cf33fd633 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -8,11 +8,8 @@ use clvmr::allocator::Allocator; use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; -use crate::compiler::cldb::hex_to_modern_sexp; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc}; use crate::compiler::dialect::KNOWN_DIALECTS; -use crate::compiler::comptypes::{ - BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc, -}; use crate::compiler::evaluate::{create_argument_captures, dequote, ArgInputs, Evaluator}; use crate::compiler::frontend::compile_helperform; use crate::compiler::preprocessor::macros::PreprocessorExtension; diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 81a1d8b23..73f75db1a 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -273,7 +273,6 @@ fn rename_in_helperform(namemap: &HashMap, Vec>, h: &HelperForm) -> HelperForm::Defmacro(mac) => HelperForm::Defmacro(DefmacData { program: Rc::new(rename_in_compileform(namemap, mac.program.clone())), ..mac.clone() - }), HelperForm::Defun(inline, defun) => HelperForm::Defun( *inline, @@ -317,7 +316,7 @@ fn rename_args_helperform(h: &HelperForm) -> HelperForm { &local_namemap, Rc::new(local_renamed_body), )), - .. mac.clone() + ..mac.clone() }) } HelperForm::Defun(inline, defun) => { diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 0fb736ec0..b17bcaec8 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -870,74 +870,6 @@ fn test_cost_reporting_0() { ); } -#[test] -fn test_assign_lambda_code_generation() { - let tname = "test_assign_lambda_code_generation.sym".to_string(); - do_basic_run(&vec![ - "run".to_string(), - "--extra-syms".to_string(), - "--symbol-output-file".to_string(), - tname.clone(), - "(mod (A) (include *standard-cl-21*) (defun F (X) (+ X 1)) (assign-lambda X (F A) X))" - .to_string(), - ]); - let read_in_file = fs::read_to_string(&tname).expect("should have dropped symbols"); - fs::remove_file(&tname).expect("should have existed"); - let decoded_symbol_file: HashMap = - serde_json::from_str(&read_in_file).expect("should decode"); - let found_wanted_symbols: Vec = decoded_symbol_file - .iter() - .filter(|(_, v)| *v == "F" || v.starts_with("letbinding")) - .map(|(k, _)| k.clone()) - .collect(); - assert_eq!(found_wanted_symbols.len(), 2); - // We should have these two functions. - assert!(found_wanted_symbols - .contains(&"ccd5be506752cebf01f9930b4c108fe18058c65e1ab57a72ca0a00d9788c7ca6".to_string())); - assert!(found_wanted_symbols - .contains(&"0a5af5ae61fae2e53cb309d4d9c2c64baf0261824823008b9cf2b21b09221e44".to_string())); -} - -#[test] -fn test_assign_lambda_code_generation_inline() { - let tname = "test_assign_inline_code_generation.sym".to_string(); - do_basic_run(&vec![ - "run".to_string(), - "--extra-syms".to_string(), - "--symbol-output-file".to_string(), - tname.clone(), - "(mod (A) (include *standard-cl-21*) (defun F (X) (+ X 1)) (assign-inline X (F A) X))" - .to_string(), - ]); - let read_in_file = fs::read_to_string(&tname).expect("should have dropped symbols"); - fs::remove_file(&tname).expect("should have existed"); - let decoded_symbol_file: HashMap = - serde_json::from_str(&read_in_file).expect("should decode"); - let found_wanted_symbols: Vec = decoded_symbol_file - .iter() - .filter(|(_, v)| *v == "F" || v.starts_with("letbinding")) - .map(|(k, _)| k.clone()) - .collect(); - assert_eq!(found_wanted_symbols.len(), 1); - // We should have these two functions. - assert!(found_wanted_symbols - .contains(&"ccd5be506752cebf01f9930b4c108fe18058c65e1ab57a72ca0a00d9788c7ca6".to_string())); -} - -#[test] -fn test_assign_fancy_final_dot_rest() { - let result_prog = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests/chia-gaming".to_string(), - "resources/tests/chia-gaming/test-last.clsp".to_string(), - ]); - let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "()".to_string()]) - .trim() - .to_string(); - assert_eq!(result, "101"); -} - #[test] fn test_strict_smoke_0() { let result = do_basic_run(&vec![ From 9f90b88ea25af6eb04fdfd1b08f912d8710d1baa Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 25 May 2023 17:49:45 -0700 Subject: [PATCH 048/196] Pull in a local add_helper method --- src/compiler/preprocessor/mod.rs | 52 +++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index cf33fd633..e28dbc98e 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -90,6 +90,56 @@ impl Preprocessor { Ok(()) } + /* + fn recurse_dependencies( + &mut self, + includes: &mut Vec, + desc: IncludeType, + ) -> Result<(), CompileErr> { + match desc { + IncludeType::Basic(desc) => { + let name_string = decode_string(&desc.name); + if KNOWN_DIALECTS.contains_key(&name_string) { + return Ok(()); + } + + let (full_name, content) = self.opts.read_new_file(self.opts.filename(), name_string)?; + includes.push(IncludeDesc { + name: full_name.as_bytes().to_vec(), + ..desc + }); + + let parsed = parse_sexp(Srcloc::start(&full_name), content.iter().copied())?; + if parsed.is_empty() { + return Ok(()); + } + + let program_form = parsed[0].clone(); + if let Some(l) = program_form.proper_list() { + for elt in l.iter() { + self.process_pp_form(includes, Rc::new(elt.clone()))?; + } + } + + Ok(()) + }, + _ => { todo!() } + } + } + */ + + fn add_helper(&mut self, h: HelperForm) { + for i in 0..=self.helpers.len() { + if i == self.helpers.len() { + self.helpers.push(h); + break; + } else if self.helpers[i].name() == h.name() { + self.helpers[i] = h; + break; + } + } + } + // Check for and apply preprocessor level macros. // This is maximally permissive. fn expand_macros(&mut self, body: Rc) -> Result, CompileErr> { @@ -184,7 +234,7 @@ impl Preprocessor { )); if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { self.evaluator.add_helper(&helper); - self.helpers.push(helper); + self.add_helper(helper.clone()); } else { return Err(CompileErr( definition.loc(), From cd764e4de54ba0bfe5675f2b555917340d971ab0 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 25 May 2023 20:39:28 -0700 Subject: [PATCH 049/196] Speed up, reduce heap traffic --- src/compiler/preprocessor/mod.rs | 39 +++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index e28dbc98e..86122194f 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -142,14 +142,37 @@ impl Preprocessor { // Check for and apply preprocessor level macros. // This is maximally permissive. - fn expand_macros(&mut self, body: Rc) -> Result, CompileErr> { + fn expand_macros(&mut self, body: Rc, start: bool) -> Result>, CompileErr> { if let SExp::Cons(l, f, r) = body.borrow() { // First expand inner macros. - let first_expanded = self.expand_macros(f.clone())?; - let rest_expanded = self.expand_macros(r.clone())?; - let new_self = Rc::new(SExp::Cons(l.clone(), first_expanded, rest_expanded)); + let first_expanded = self.expand_macros(f.clone(), true)?; + let rest_expanded = self.expand_macros(r.clone(), false)?; + let new_self = + match (first_expanded, rest_expanded) { + (None, None) => None, + (Some(f), None) => Some(Rc::new(SExp::Cons( + l.clone(), + f.clone(), + r.clone() + ))), + (None, Some(r)) => Some(Rc::new(SExp::Cons( + l.clone(), + f.clone(), + r.clone() + ))), + (Some(f),Some(r)) => Some(Rc::new(SExp::Cons( + l.clone(), + f.clone(), + r.clone() + ))) + }; + + if !start { + return Ok(new_self); + } + if let Ok(NodeSel::Cons((_, name), args)) = - NodeSel::Cons(Atom::Here(()), ThisNode::Here).select_nodes(new_self.clone()) + NodeSel::Cons(Atom::Here(()), ThisNode::Here).select_nodes(new_self.clone().unwrap_or_else(|| body.clone())) { // See if it's a form that calls one of our macros. for m in self.helpers.iter() { @@ -183,7 +206,7 @@ impl Preprocessor { )?; if let Ok(unquoted) = dequote(body.loc(), res) { - return Ok(unquoted); + return Ok(Some(unquoted)); } else { return Err(CompileErr( body.loc(), @@ -197,7 +220,7 @@ impl Preprocessor { return Ok(new_self); } - Ok(body) + Ok(None) } // If it's a defmac (preprocessor level macro), add it to the evaulator. @@ -256,7 +279,7 @@ impl Preprocessor { includes: &mut Vec, unexpanded_body: Rc, ) -> Result>, CompileErr> { - let body = self.expand_macros(unexpanded_body)?; + let body = self.expand_macros(unexpanded_body.clone(), true)?.unwrap_or_else(|| unexpanded_body.clone()); // Support using the preprocessor to collect dependencies recursively. let included: Option = body .proper_list() From 8e254c24beca952a51fab9ed08d269133dfaf3d8 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 29 May 2023 17:05:46 -0700 Subject: [PATCH 050/196] fmt + clippy --- src/compiler/preprocessor/mod.rs | 38 ++++++++++++++------------------ 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 86122194f..ba6f5c9cd 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -142,37 +142,29 @@ impl Preprocessor { // Check for and apply preprocessor level macros. // This is maximally permissive. - fn expand_macros(&mut self, body: Rc, start: bool) -> Result>, CompileErr> { + fn expand_macros( + &mut self, + body: Rc, + start: bool, + ) -> Result>, CompileErr> { if let SExp::Cons(l, f, r) = body.borrow() { // First expand inner macros. let first_expanded = self.expand_macros(f.clone(), true)?; let rest_expanded = self.expand_macros(r.clone(), false)?; - let new_self = - match (first_expanded, rest_expanded) { - (None, None) => None, - (Some(f), None) => Some(Rc::new(SExp::Cons( - l.clone(), - f.clone(), - r.clone() - ))), - (None, Some(r)) => Some(Rc::new(SExp::Cons( - l.clone(), - f.clone(), - r.clone() - ))), - (Some(f),Some(r)) => Some(Rc::new(SExp::Cons( - l.clone(), - f.clone(), - r.clone() - ))) - }; + let new_self = match (first_expanded, rest_expanded) { + (None, None) => None, + (Some(f), None) => Some(Rc::new(SExp::Cons(l.clone(), f, r.clone()))), + (None, Some(r)) => Some(Rc::new(SExp::Cons(l.clone(), f.clone(), r))), + (Some(f), Some(r)) => Some(Rc::new(SExp::Cons(l.clone(), f, r))), + }; if !start { return Ok(new_self); } if let Ok(NodeSel::Cons((_, name), args)) = - NodeSel::Cons(Atom::Here(()), ThisNode::Here).select_nodes(new_self.clone().unwrap_or_else(|| body.clone())) + NodeSel::Cons(Atom::Here(()), ThisNode::Here) + .select_nodes(new_self.clone().unwrap_or_else(|| body.clone())) { // See if it's a form that calls one of our macros. for m in self.helpers.iter() { @@ -279,7 +271,9 @@ impl Preprocessor { includes: &mut Vec, unexpanded_body: Rc, ) -> Result>, CompileErr> { - let body = self.expand_macros(unexpanded_body.clone(), true)?.unwrap_or_else(|| unexpanded_body.clone()); + let body = self + .expand_macros(unexpanded_body.clone(), true)? + .unwrap_or_else(|| unexpanded_body.clone()); // Support using the preprocessor to collect dependencies recursively. let included: Option = body .proper_list() From 0d193ff17dbfe5da58762a927aa1bba6eb78b4f8 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 25 May 2023 20:52:36 -0700 Subject: [PATCH 051/196] Rename defuns so they don't overlap real uses when they occur --- src/compiler/preprocessor/mod.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index ba6f5c9cd..a8db832b4 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -25,6 +25,27 @@ struct Preprocessor { helpers: Vec, } +fn compose_defconst(loc: Srcloc, name: &[u8], sexp: Rc) -> Rc { + Rc::new(enlist( + loc.clone(), + vec![ + Rc::new(SExp::Atom(loc.clone(), b"defconst".to_vec())), + Rc::new(SExp::Atom(loc.clone(), name.to_vec())), + Rc::new(SExp::Cons( + loc.clone(), + Rc::new(SExp::Atom(loc, vec![1])), + sexp, + )), + ], + )) +} + +fn make_defmac_name(name: &[u8]) -> Vec { + let mut res = b"__chia__defmac__".to_vec(); + res.append(&mut name.to_vec()); + res +} + impl Preprocessor { pub fn new(opts: Rc) -> Self { let runner = Rc::new(DefaultProgramRunner::new()); @@ -166,11 +187,13 @@ impl Preprocessor { NodeSel::Cons(Atom::Here(()), ThisNode::Here) .select_nodes(new_self.clone().unwrap_or_else(|| body.clone())) { + let defmac_name = make_defmac_name(&name); + // See if it's a form that calls one of our macros. for m in self.helpers.iter() { if let HelperForm::Defun(_, mdata) = &m { // We record upfront macros - if mdata.name != name { + if mdata.name != defmac_name { continue; } @@ -243,7 +266,7 @@ impl Preprocessor { Rc::new(SExp::atom_from_string(defmac_loc, "defun")), Rc::new(SExp::Cons( nl.clone(), - Rc::new(SExp::Atom(nl, name)), + Rc::new(SExp::Atom(nl, make_defmac_name(&name))), Rc::new(SExp::Cons(args.loc(), args.clone(), body)), )), )); From afaf3f0f949adaf709366afafb66a18d283fcad3 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 25 May 2023 20:56:54 -0700 Subject: [PATCH 052/196] cherry-pick + fmt + clippy --- src/compiler/preprocessor/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index a8db832b4..a671a76fe 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -25,6 +25,7 @@ struct Preprocessor { helpers: Vec, } +/* fn compose_defconst(loc: Srcloc, name: &[u8], sexp: Rc) -> Rc { Rc::new(enlist( loc.clone(), @@ -39,6 +40,7 @@ fn compose_defconst(loc: Srcloc, name: &[u8], sexp: Rc) -> Rc { ], )) } +*/ fn make_defmac_name(name: &[u8]) -> Vec { let mut res = b"__chia__defmac__".to_vec(); @@ -150,6 +152,7 @@ impl Preprocessor { */ fn add_helper(&mut self, h: HelperForm) { + self.evaluator.add_helper(&h); for i in 0..=self.helpers.len() { if i == self.helpers.len() { self.helpers.push(h); @@ -271,8 +274,7 @@ impl Preprocessor { )), )); if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { - self.evaluator.add_helper(&helper); - self.add_helper(helper.clone()); + self.add_helper(helper); } else { return Err(CompileErr( definition.loc(), @@ -280,7 +282,7 @@ impl Preprocessor { )); } } else if let Some(helper) = compile_helperform(self.opts.clone(), definition)? { - self.evaluator.add_helper(&helper); + self.add_helper(helper); } } } From ae6472d444f109fe0a13a536a71820a8751a4f82 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 25 May 2023 21:01:34 -0700 Subject: [PATCH 053/196] Remove persistent evaluator, use a local one. now there's only one helper list and we control it from here. --- src/compiler/preprocessor/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index a671a76fe..373bbffd0 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -6,7 +6,10 @@ use std::rc::Rc; use clvmr::allocator::Allocator; -use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; +use crate::classic::clvm_tools::clvmc::compile_clvm_text_maybe_opt; +use crate::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; +use crate::compiler::clvm::convert_from_clvm_rs; +ne helper list and we control it from here.) use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc}; use crate::compiler::dialect::KNOWN_DIALECTS; @@ -21,7 +24,7 @@ use crate::util::ErrInto; struct Preprocessor { opts: Rc, - evaluator: Evaluator, + runner: Rc, helpers: Vec, } @@ -51,11 +54,9 @@ fn make_defmac_name(name: &[u8]) -> Vec { impl Preprocessor { pub fn new(opts: Rc) -> Self { let runner = Rc::new(DefaultProgramRunner::new()); - let mut eval = Evaluator::new(opts.clone(), runner, Vec::new()); - eval.add_extension(Rc::new(PreprocessorExtension::new())); Preprocessor { opts: opts.clone(), - evaluator: eval, + runner, helpers: Vec::new(), } } @@ -152,7 +153,6 @@ impl Preprocessor { */ fn add_helper(&mut self, h: HelperForm) { - self.evaluator.add_helper(&h); for i in 0..=self.helpers.len() { if i == self.helpers.len() { self.helpers.push(h); @@ -214,7 +214,9 @@ impl Preprocessor { mdata.args.clone(), )?; - let res = self.evaluator.shrink_bodyform( + let mut eval = Evaluator::new(self.opts.clone(), self.runner.clone(), self.helpers.clone()); + eval.add_extension(Rc::new(PreprocessorExtension::new())); + let res = eval.shrink_bodyform( &mut allocator, mdata.args.clone(), ¯o_arg_env, From affb0445de1283d41f32f60e58fdd8853c440d8a Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 29 May 2023 17:30:30 -0700 Subject: [PATCH 054/196] fmt --- src/compiler/preprocessor/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 373bbffd0..0e3e37d9a 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -6,10 +6,7 @@ use std::rc::Rc; use clvmr::allocator::Allocator; -use crate::classic::clvm_tools::clvmc::compile_clvm_text_maybe_opt; use crate::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; -use crate::compiler::clvm::convert_from_clvm_rs; -ne helper list and we control it from here.) use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc}; use crate::compiler::dialect::KNOWN_DIALECTS; @@ -214,7 +211,11 @@ impl Preprocessor { mdata.args.clone(), )?; - let mut eval = Evaluator::new(self.opts.clone(), self.runner.clone(), self.helpers.clone()); + let mut eval = Evaluator::new( + self.opts.clone(), + self.runner.clone(), + self.helpers.clone(), + ); eval.add_extension(Rc::new(PreprocessorExtension::new())); let res = eval.shrink_bodyform( &mut allocator, From 4396883139abe0cb5473fb465dac0d5f43fe9929 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 26 May 2023 14:12:56 -0700 Subject: [PATCH 055/196] more moves --- src/compiler/evaluate.rs | 61 ++++++++++++++++++++++---------- src/compiler/preprocessor/mod.rs | 7 ++++ 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 893f20489..66d13bcdc 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -17,7 +17,7 @@ use crate::compiler::comptypes::{ }; use crate::compiler::frontend::frontend; use crate::compiler::runtypes::RunFailure; -use crate::compiler::sexp::SExp; +use crate::compiler::sexp::{enlist, SExp}; use crate::compiler::srcloc::Srcloc; use crate::compiler::stackvisit::{HasDepthLimit, VisitedMarker}; use crate::util::{number_from_u8, u8_from_number, Number}; @@ -700,6 +700,45 @@ impl<'info> Evaluator { } } + fn defmac_ordering(&self) -> bool { + let dialect = self.opts.dialect(); + dialect.strict || dialect.stepping.unwrap_or(21) > 22 + } + + fn make_com_module( + &self, + l: &Srcloc, + prog_args: Rc, + body: Rc + ) -> Rc { + let end_of_list = + if self.defmac_ordering() { + let mut mod_list: Vec> = self.helpers.iter().map(|h| { + h.to_sexp() + }).collect(); + mod_list.push(body); + Rc::new(enlist(l.clone(), &mod_list)) + } else { + let mut end_of_list = Rc::new(SExp::Cons( + l.clone(), + body, + Rc::new(SExp::Nil(l.clone())), + )); + + for h in self.helpers.iter() { + end_of_list = Rc::new(SExp::Cons(l.clone(), h.to_sexp(), end_of_list)); + } + + end_of_list + }; + + Rc::new(SExp::Cons( + l.clone(), + Rc::new(SExp::Atom(l.clone(), "mod".as_bytes().to_vec())), + Rc::new(SExp::Cons(l.clone(), prog_args, end_of_list)), + )) + } + #[allow(clippy::too_many_arguments)] fn invoke_primitive( &self, @@ -725,23 +764,9 @@ impl<'info> Evaluator { prog_args, )))) } else if call_name == "com".as_bytes() { - let mut end_of_list = Rc::new(SExp::Cons( - l.clone(), - arguments_to_convert[0].to_sexp(), - Rc::new(SExp::Nil(l.clone())), - )); - - for h in self.helpers.iter() { - end_of_list = Rc::new(SExp::Cons(l.clone(), h.to_sexp(), end_of_list)) - } - - let use_body = SExp::Cons( - l.clone(), - Rc::new(SExp::Atom(l.clone(), "mod".as_bytes().to_vec())), - Rc::new(SExp::Cons(l, prog_args, end_of_list)), - ); - - let compiled = self.compile_code(allocator, false, Rc::new(use_body))?; + let use_body = self.make_com_module(&l, prog_args.clone(), arguments_to_convert[0].to_sexp()); + eprintln!("use_body {use_body}"); + let compiled = self.compile_code(allocator, false, use_body)?; let compiled_borrowed: &SExp = compiled.borrow(); Ok(Rc::new(BodyForm::Quoted(compiled_borrowed.clone()))) } else { diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 0e3e37d9a..8fc6e0081 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -217,6 +217,11 @@ impl Preprocessor { self.helpers.clone(), ); eval.add_extension(Rc::new(PreprocessorExtension::new())); + eprintln!("expand macro {}", decode_string(&name)); + for (n,v) in macro_arg_env.iter() { + eprintln!("- {} = {}", decode_string(n), v.to_sexp()); + } + let res = eval.shrink_bodyform( &mut allocator, mdata.args.clone(), @@ -226,6 +231,8 @@ impl Preprocessor { None, )?; + eprintln!("expanded => {}", res.to_sexp()); + if let Ok(unquoted) = dequote(body.loc(), res) { return Ok(Some(unquoted)); } else { From 991381e496118f037757d70cae684d54c62adee6 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 29 May 2023 17:37:25 -0700 Subject: [PATCH 056/196] fmt + clippy --- src/compiler/evaluate.rs | 40 ++++++++++++-------------------- src/compiler/preprocessor/mod.rs | 2 +- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 66d13bcdc..56dd40d84 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -705,32 +705,21 @@ impl<'info> Evaluator { dialect.strict || dialect.stepping.unwrap_or(21) > 22 } - fn make_com_module( - &self, - l: &Srcloc, - prog_args: Rc, - body: Rc - ) -> Rc { - let end_of_list = - if self.defmac_ordering() { - let mut mod_list: Vec> = self.helpers.iter().map(|h| { - h.to_sexp() - }).collect(); - mod_list.push(body); - Rc::new(enlist(l.clone(), &mod_list)) - } else { - let mut end_of_list = Rc::new(SExp::Cons( - l.clone(), - body, - Rc::new(SExp::Nil(l.clone())), - )); + fn make_com_module(&self, l: &Srcloc, prog_args: Rc, body: Rc) -> Rc { + let end_of_list = if self.defmac_ordering() { + let mut mod_list: Vec> = self.helpers.iter().map(|h| h.to_sexp()).collect(); + mod_list.push(body); + Rc::new(enlist(l.clone(), mod_list)) + } else { + let mut end_of_list = + Rc::new(SExp::Cons(l.clone(), body, Rc::new(SExp::Nil(l.clone())))); - for h in self.helpers.iter() { - end_of_list = Rc::new(SExp::Cons(l.clone(), h.to_sexp(), end_of_list)); - } + for h in self.helpers.iter() { + end_of_list = Rc::new(SExp::Cons(l.clone(), h.to_sexp(), end_of_list)); + } - end_of_list - }; + end_of_list + }; Rc::new(SExp::Cons( l.clone(), @@ -764,7 +753,8 @@ impl<'info> Evaluator { prog_args, )))) } else if call_name == "com".as_bytes() { - let use_body = self.make_com_module(&l, prog_args.clone(), arguments_to_convert[0].to_sexp()); + let use_body = + self.make_com_module(&l, prog_args, arguments_to_convert[0].to_sexp()); eprintln!("use_body {use_body}"); let compiled = self.compile_code(allocator, false, use_body)?; let compiled_borrowed: &SExp = compiled.borrow(); diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 8fc6e0081..a092dddaf 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -218,7 +218,7 @@ impl Preprocessor { ); eval.add_extension(Rc::new(PreprocessorExtension::new())); eprintln!("expand macro {}", decode_string(&name)); - for (n,v) in macro_arg_env.iter() { + for (n, v) in macro_arg_env.iter() { eprintln!("- {} = {}", decode_string(n), v.to_sexp()); } From 432272b6ba47647d9d2c1ea5285cb2e293ee3b84 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 29 May 2023 12:09:37 -0700 Subject: [PATCH 057/196] Fix a bug that kept macros relying on macros from evaluating in some circumstances --- src/compiler/evaluate.rs | 2 +- src/tests/compiler/preprocessor.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 56dd40d84..07c8d21f4 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -1330,7 +1330,7 @@ impl<'info> Evaluator { // primitive. let updated_opts = self .opts - .set_stdenv(!in_defun) + .set_stdenv(!in_defun && !self.opts.dialect().strict) .set_in_defun(in_defun) .set_frontend_opt(false); diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 5ccfd906d..b0873b202 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -1,3 +1,11 @@ +use std::rc::Rc; +use crate::compiler::comptypes::CompilerOpts; +use crate::compiler::compiler::DefaultCompilerOpts; +use crate::compiler::dialect::AcceptedDialect; +use crate::compiler::preprocessor::preprocess; +use crate::compiler::sexp::parse_sexp; +use crate::compiler::srcloc::Srcloc; + use crate::tests::compiler::compiler::run_string; #[test] @@ -503,3 +511,25 @@ fn test_defmac_number_to_string() { let res = run_string(&prog, &"(37)".to_string()).unwrap(); assert_eq!(res.to_string(), "136"); } + +#[test] +fn test_preprocess_basic_list() { + let file = "*test*"; + let input_form_set = indoc! {"( + (include *strict-cl-21*) + (list 1 2 3) + )"}; + let parsed_forms = parse_sexp(Srcloc::start(file), input_form_set.bytes()).expect("should parse"); + let opts: Rc = + Rc::new(DefaultCompilerOpts::new(file)).set_dialect(AcceptedDialect { + stepping: Some(21), + strict: true, + }); + let mut includes = Vec::new(); + let pp = preprocess( + opts.clone(), + &mut includes, + parsed_forms[0].clone() + ).expect("should preprocess"); + assert_eq!(pp[pp.len()-1].to_string(), "(4 1 (4 2 (4 3 ())))"); +} From 4daa88e09e50ceed0c708d92cb4b77257e060b32 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 29 May 2023 13:21:28 -0700 Subject: [PATCH 058/196] Added new tests for strict mode with modern macros --- src/tests/classic/run.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index b17bcaec8..c08d615e7 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -896,16 +896,28 @@ fn test_strict_smoke_1() { assert_eq!(result, "15"); } -/* #[test] fn test_strict_list_fail() { - let result_prog = do_basic_run(&vec![ + let result = do_basic_run(&vec![ "run".to_string(), "-i".to_string(), "resources/tests/strict".to_string(), "resources/tests/strict/strict-list-fail.clsp".to_string(), ]); - eprintln!("result_prog {result_prog}"); - todo!(); + assert!(result.contains("Unbound")); + assert!(result.contains("X2")); +} + +#[test] +fn test_strict_list_pass() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/strict-list-pass.clsp".to_string(), + ]); + let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "(13)".to_string()]) + .trim() + .to_string(); + assert_eq!(result, "(strlen 14 15)"); } -*/ From 8e04372fb715d0d363b2d33891512e56919dc3ce Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 29 May 2023 17:43:26 -0700 Subject: [PATCH 059/196] fmt + clippy --- src/compiler/evaluate.rs | 3 +- src/compiler/preprocessor/mod.rs | 45 ------------------------------ src/tests/compiler/preprocessor.rs | 16 +++++------ 3 files changed, 8 insertions(+), 56 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 07c8d21f4..7bc6ee80d 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -753,8 +753,7 @@ impl<'info> Evaluator { prog_args, )))) } else if call_name == "com".as_bytes() { - let use_body = - self.make_com_module(&l, prog_args, arguments_to_convert[0].to_sexp()); + let use_body = self.make_com_module(&l, prog_args, arguments_to_convert[0].to_sexp()); eprintln!("use_body {use_body}"); let compiled = self.compile_code(allocator, false, use_body)?; let compiled_borrowed: &SExp = compiled.borrow(); diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index a092dddaf..5b7f182d7 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -111,44 +111,6 @@ impl Preprocessor { Ok(()) } - /* - fn recurse_dependencies( - &mut self, - includes: &mut Vec, - desc: IncludeType, - ) -> Result<(), CompileErr> { - match desc { - IncludeType::Basic(desc) => { - let name_string = decode_string(&desc.name); - if KNOWN_DIALECTS.contains_key(&name_string) { - return Ok(()); - } - - let (full_name, content) = self.opts.read_new_file(self.opts.filename(), name_string)?; - includes.push(IncludeDesc { - name: full_name.as_bytes().to_vec(), - ..desc - }); - - let parsed = parse_sexp(Srcloc::start(&full_name), content.iter().copied())?; - if parsed.is_empty() { - return Ok(()); - } - - let program_form = parsed[0].clone(); - if let Some(l) = program_form.proper_list() { - for elt in l.iter() { - self.process_pp_form(includes, Rc::new(elt.clone()))?; - } - } - - Ok(()) - }, - _ => { todo!() } - } - } - */ - fn add_helper(&mut self, h: HelperForm) { for i in 0..=self.helpers.len() { if i == self.helpers.len() { @@ -217,11 +179,6 @@ impl Preprocessor { self.helpers.clone(), ); eval.add_extension(Rc::new(PreprocessorExtension::new())); - eprintln!("expand macro {}", decode_string(&name)); - for (n, v) in macro_arg_env.iter() { - eprintln!("- {} = {}", decode_string(n), v.to_sexp()); - } - let res = eval.shrink_bodyform( &mut allocator, mdata.args.clone(), @@ -231,8 +188,6 @@ impl Preprocessor { None, )?; - eprintln!("expanded => {}", res.to_sexp()); - if let Ok(unquoted) = dequote(body.loc(), res) { return Ok(Some(unquoted)); } else { diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index b0873b202..1d8ab82b9 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -1,10 +1,10 @@ -use std::rc::Rc; -use crate::compiler::comptypes::CompilerOpts; use crate::compiler::compiler::DefaultCompilerOpts; +use crate::compiler::comptypes::CompilerOpts; use crate::compiler::dialect::AcceptedDialect; use crate::compiler::preprocessor::preprocess; use crate::compiler::sexp::parse_sexp; use crate::compiler::srcloc::Srcloc; +use std::rc::Rc; use crate::tests::compiler::compiler::run_string; @@ -519,17 +519,15 @@ fn test_preprocess_basic_list() { (include *strict-cl-21*) (list 1 2 3) )"}; - let parsed_forms = parse_sexp(Srcloc::start(file), input_form_set.bytes()).expect("should parse"); + let parsed_forms = + parse_sexp(Srcloc::start(file), input_form_set.bytes()).expect("should parse"); let opts: Rc = Rc::new(DefaultCompilerOpts::new(file)).set_dialect(AcceptedDialect { stepping: Some(21), strict: true, }); let mut includes = Vec::new(); - let pp = preprocess( - opts.clone(), - &mut includes, - parsed_forms[0].clone() - ).expect("should preprocess"); - assert_eq!(pp[pp.len()-1].to_string(), "(4 1 (4 2 (4 3 ())))"); + let pp = preprocess(opts.clone(), &mut includes, parsed_forms[0].clone()) + .expect("should preprocess"); + assert_eq!(pp[pp.len() - 1].to_string(), "(4 1 (4 2 (4 3 ())))"); } From 62cfdb96920552047cfc8f23536d92611dbfc8bc Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 29 May 2023 17:45:59 -0700 Subject: [PATCH 060/196] remove spam --- src/compiler/evaluate.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 7bc6ee80d..63068ae69 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -754,7 +754,6 @@ impl<'info> Evaluator { )))) } else if call_name == "com".as_bytes() { let use_body = self.make_com_module(&l, prog_args, arguments_to_convert[0].to_sexp()); - eprintln!("use_body {use_body}"); let compiled = self.compile_code(allocator, false, use_body)?; let compiled_borrowed: &SExp = compiled.borrow(); Ok(Rc::new(BodyForm::Quoted(compiled_borrowed.clone()))) From 583d2506906c57746350f39402939fe907a35057 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 30 May 2023 08:28:46 -0700 Subject: [PATCH 061/196] Add test with deeper macro nesting --- resources/tests/strict/strict-nested-list.clsp | 4 ++++ src/tests/classic/run.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 resources/tests/strict/strict-nested-list.clsp diff --git a/resources/tests/strict/strict-nested-list.clsp b/resources/tests/strict/strict-nested-list.clsp new file mode 100644 index 000000000..6bc4bddb4 --- /dev/null +++ b/resources/tests/strict/strict-nested-list.clsp @@ -0,0 +1,4 @@ +(mod (X) + (include *strict-cl-21*) + (list X (list X) (list (list X))) + ) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index c08d615e7..a5e696ac3 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -921,3 +921,17 @@ fn test_strict_list_pass() { .to_string(); assert_eq!(result, "(strlen 14 15)"); } + +#[test] +fn test_strict_nested_list_pass() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/strict-nested-list.clsp".to_string(), + ]); + let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "(13)".to_string()]) + .trim() + .to_string(); + assert_eq!(result, "(strlen (strlen) ((strlen)))"); +} From 7339e26ab32154ecf15707fc5a9d298cd26739b6 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 30 May 2023 08:51:53 -0700 Subject: [PATCH 062/196] More moderately complex tests of what this kind of macro system can do --- src/tests/classic/run.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index a5e696ac3..ea71d1874 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -935,3 +935,29 @@ fn test_strict_nested_list_pass() { .to_string(); assert_eq!(result, "(strlen (strlen) ((strlen)))"); } + +#[test] +fn test_double_constant_pass() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/double-constant-pass.clsp".to_string(), + ]); + let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "()".to_string()]) + .trim() + .to_string(); + assert_eq!(result, "198"); +} + +#[test] +fn test_double_constant_fail() { + let result = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/double-constant-fail.clsp".to_string(), + ]); + assert!(result.contains("not a number given to only-integers")); + assert!(result.contains("\"hithere\"")); +} From a2bcc3101d6e560e212556a77101d32bca794860 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 30 May 2023 08:52:16 -0700 Subject: [PATCH 063/196] Add test files --- .../tests/strict/double-constant-fail.clsp | 24 +++++++++++++++++++ .../tests/strict/double-constant-pass.clsp | 24 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 resources/tests/strict/double-constant-fail.clsp create mode 100644 resources/tests/strict/double-constant-pass.clsp diff --git a/resources/tests/strict/double-constant-fail.clsp b/resources/tests/strict/double-constant-fail.clsp new file mode 100644 index 000000000..7af9d1e23 --- /dev/null +++ b/resources/tests/strict/double-constant-fail.clsp @@ -0,0 +1,24 @@ +(mod (X) + (include *strict-cl-21*) + + ;; A macro-level function to pass through only real integers. + (defun pass-through-integers (X) + (if (not (number? X)) + (x "not a number given to only-integers" X) + X + ) + ) + + ;; A macro which at preprocessing time throws if the given argument + ;; wasn't a lexical integer. + (defmac only-integers (X) (pass-through-integers X)) + + ;; Note: when macro expanding, N is the N argument to the body of + ;; the double macro, not the integer literal, so we use the function + ;; version of pass-through-integers in the macro body. + (defmac double (N) (* 2 (pass-through-integers N))) + + ;; Here the macro form of only-integers can determine whether the + ;; double macro produced an integer or some other expression. + (only-integers (double "hithere")) + ) diff --git a/resources/tests/strict/double-constant-pass.clsp b/resources/tests/strict/double-constant-pass.clsp new file mode 100644 index 000000000..7b50bd1ee --- /dev/null +++ b/resources/tests/strict/double-constant-pass.clsp @@ -0,0 +1,24 @@ +(mod (X) + (include *strict-cl-21*) + + ;; A macro-level function to pass through only real integers. + (defun pass-through-integers (X) + (if (not (number? X)) + (x "not a number given to only-integers" X) + X + ) + ) + + ;; A macro which at preprocessing time throws if the given argument + ;; wasn't a lexical integer. + (defmac only-integers (X) (pass-through-integers X)) + + ;; Note: when macro expanding, N is the N argument to the body of + ;; the double macro, not the integer literal, so we use the function + ;; version of pass-through-integers in the macro body. + (defmac double (N) (* 2 (pass-through-integers N))) + + ;; Here the macro form of only-integers can determine whether the + ;; double macro produced an integer or some other expression. + (only-integers (double 99)) + ) From 282b08f6274986ee5c2968f866b092fa91f2c6ce Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 30 May 2023 12:10:52 -0700 Subject: [PATCH 064/196] Plumb down new primitives when running with extensions. Add test using this. --- src/compiler/cldb.rs | 1 + src/compiler/clvm.rs | 24 +++++++++++-- src/compiler/codegen.rs | 2 ++ src/compiler/compiler.rs | 5 +++ src/compiler/comptypes.rs | 2 ++ src/compiler/evaluate.rs | 53 ++++++++++++++++++++++++++++- src/compiler/optimize.rs | 1 + src/compiler/preprocessor/macros.rs | 16 ++++++++- src/compiler/preprocessor/mod.rs | 5 +-- src/tests/classic/run.rs | 32 +++++++++++++++++ src/tests/classic/stage_2.rs | 3 ++ src/tests/compiler/compiler.rs | 1 + 12 files changed, 138 insertions(+), 7 deletions(-) diff --git a/src/compiler/cldb.rs b/src/compiler/cldb.rs index 95df3dcd2..11b4c7f59 100644 --- a/src/compiler/cldb.rs +++ b/src/compiler/cldb.rs @@ -150,6 +150,7 @@ impl CldbRun { self.runner.clone(), self.prim_map.clone(), &self.step, + None, ), }; diff --git a/src/compiler/clvm.rs b/src/compiler/clvm.rs index 5c2656c80..a1e535532 100644 --- a/src/compiler/clvm.rs +++ b/src/compiler/clvm.rs @@ -20,6 +20,11 @@ use crate::compiler::srcloc::Srcloc; use crate::util::{number_from_u8, u8_from_number, Number}; +/// Provide a way of intercepting and running new primitives. +pub trait PrimOverride { + fn try_handle(&self, head: Rc, context: Rc, tail: Rc) -> Result>, RunFailure>; +} + /// An object which contains the state of a running CLVM program in a compact /// form. /// @@ -161,7 +166,7 @@ fn translate_head( Some(v) => Ok(Rc::new(v.with_loc(l.clone()))), }, SExp::Cons(_l, _a, nil) => match nil.borrow() { - SExp::Nil(_l1) => run(allocator, runner, prim_map, sexp.clone(), context, None), + SExp::Nil(_l1) => run(allocator, runner, prim_map, sexp.clone(), context, None, None), _ => Err(RunFailure::RunErr( sexp.loc(), format!("Unexpected head form in clvm {sexp}"), @@ -396,6 +401,7 @@ pub fn run_step( runner: Rc, prim_map: Rc, Rc>>, step_: &RunStep, + prim_override: Option<&dyn PrimOverride>, ) -> Result { let mut step = step_.clone(); @@ -499,7 +505,7 @@ pub fn run_step( } } } - RunStep::Op(head, _context, tail, None, parent) => { + RunStep::Op(head, context, tail, None, parent) => { let aval = atom_value(head.clone())?; let apply_atom = 2_i32.to_bigint().unwrap(); let if_atom = 3_i32.to_bigint().unwrap(); @@ -517,6 +523,16 @@ pub fn run_step( -1 }; + if let Some(ovr) = prim_override { + if let Some(res) = + ovr.try_handle(head.clone(), context.clone(), tail.clone())? + { + return Ok(RunStep::OpResult( + res.loc(), res.clone(), parent.clone() + )); + } + } + let op = if aval == apply_atom { "apply".to_string() } else if aval == if_atom { @@ -632,6 +648,7 @@ pub fn run( prim_map: Rc, Rc>>, sexp_: Rc, context_: Rc, + prim_override: Option<&dyn PrimOverride>, iter_limit: Option, ) -> Result, RunFailure> { let mut step = start_step(sexp_, context_); @@ -644,7 +661,7 @@ pub fn run( } } iters += 1; - step = run_step(allocator, runner.clone(), prim_map.clone(), &step)?; + step = run_step(allocator, runner.clone(), prim_map.clone(), &step, prim_override.clone())?; if let RunStep::Done(_, x) = step { return Ok(x); } @@ -684,6 +701,7 @@ pub fn parse_and_run( prim_map, code[0].clone(), args[0].clone(), + None, step_limit, ) } diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 064512485..828f7418d 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -272,6 +272,7 @@ pub fn process_macro_call( opts.prim_map(), code, Rc::new(args_to_macro), + None, Some(MACRO_TIME_LIMIT), ) .map_err(|e| match e { @@ -994,6 +995,7 @@ fn start_codegen( opts.prim_map(), Rc::new(code), Rc::new(SExp::Nil(defc.loc.clone())), + None, Some(CONST_EVAL_LIMIT), ) .map_err(|r| { diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index ec9577096..dd599a61b 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -310,6 +310,11 @@ impl CompilerOpts for DefaultCompilerOpts { copy.start_env = start_env; Rc::new(copy) } + fn set_prim_map(&self, prims: Rc, Rc>>) -> Rc { + let mut copy = self.clone(); + copy.prim_map = prims; + Rc::new(copy) + } fn read_new_file( &self, diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 500590e74..1c86274a4 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -357,6 +357,8 @@ pub trait CompilerOpts { fn set_code_generator(&self, new_compiler: PrimaryCodegen) -> Rc; /// Set the environment shape to assume. fn set_start_env(&self, start_env: Option>) -> Rc; + /// Set the primitive map in use so we can add custom primitives. + fn set_prim_map(&self, new_map: Rc, Rc>>) -> Rc; /// Using the search paths list we have, try to read a file by name, /// Returning the expanded path to the file and its content. diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 63068ae69..d4142a0b2 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -9,7 +9,7 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::run; +use crate::compiler::clvm::{PrimOverride, run}; use crate::compiler::codegen::codegen; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ @@ -134,6 +134,56 @@ pub struct Evaluator { ignore_exn: bool, } +fn compile_to_run_err(e: CompileErr) -> RunFailure { + match e { + CompileErr(l, e) => { + RunFailure::RunErr(l.clone(), e.clone()) + } + } +} + +impl PrimOverride for Evaluator { + fn try_handle(&self, head: Rc, _context: Rc, tail: Rc) -> Result>, RunFailure> { + let have_args: Vec> = + if let Some(args_list) = tail + .proper_list() { + args_list + .iter() + .map(|e| Rc::new(BodyForm::Quoted(e.clone()))) + .collect() + } else { + return Ok(None); + }; + + if let SExp::Atom(hl, head_atom) = head.borrow() { + let mut call_args = + vec![Rc::new(BodyForm::Value(SExp::Atom(hl.clone(), head_atom.clone())))]; + call_args.append(&mut have_args.clone()); + let call_form = Rc::new(BodyForm::Call(head.loc(), call_args)); + + for x in self.extensions.iter() { + if let Some(res) = + x.try_eval( + self, + Rc::new(SExp::Nil(head.loc())), + &HashMap::new(), + &head.loc(), + &head_atom, + &have_args, + call_form.clone(), + ).map_err(compile_to_run_err)? + { + return dequote(head.loc(), res) + .map_err(compile_to_run_err) + .map(Some); + } + } + } + + Ok(None) + } +} + fn select_helper(bindings: &[HelperForm], name: &[u8]) -> Option { for b in bindings.iter() { if b.name() == name { @@ -1305,6 +1355,7 @@ impl<'info> Evaluator { self.prims.clone(), prim, args, + Some(self), Some(PRIM_RUN_LIMIT), ) .map_err(|e| match e { diff --git a/src/compiler/optimize.rs b/src/compiler/optimize.rs index 03dda32e9..901c93ebf 100644 --- a/src/compiler/optimize.rs +++ b/src/compiler/optimize.rs @@ -89,6 +89,7 @@ pub fn optimize_expr( opts.prim_map(), code.to_sexp(), Rc::new(SExp::Nil(l)), + None, Some(CONST_FOLD_LIMIT), ) .map(|x| { diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 28abf435d..6d6375d2c 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -9,7 +9,7 @@ use num_traits::ToPrimitive; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::compiler::clvm::truthy; -use crate::compiler::comptypes::{BodyForm, CompileErr}; +use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts}; use crate::compiler::evaluate::{EvalExtension, Evaluator}; use crate::compiler::preprocessor::dequote; use crate::compiler::sexp::{decode_string, SExp}; @@ -771,6 +771,20 @@ impl PreprocessorExtension { extfuns: HashMap::from(extfuns), } } + + /// Introduce new primitive names for the operators we use to bootstrap macros. + pub fn enrich_prims(&self, opts: Rc) -> Rc { + let old_prim_map = opts.prim_map(); + let old_prim_map_borrowed: &HashMap, Rc> = old_prim_map.borrow(); + let mut new_prim_map_cloned = old_prim_map_borrowed.clone(); + let srcloc = Srcloc::start("*defmac*"); + + for (f, _) in self.extfuns.iter() { + new_prim_map_cloned.insert(f.clone(), Rc::new(SExp::Atom(srcloc.clone(), f.clone()))); + } + + opts.set_prim_map(Rc::new(new_prim_map_cloned)) + } } impl EvalExtension for PreprocessorExtension { diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 5b7f182d7..1e935d30a 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -173,12 +173,13 @@ impl Preprocessor { mdata.args.clone(), )?; + let ppext = Rc::new(PreprocessorExtension::new()); let mut eval = Evaluator::new( - self.opts.clone(), + ppext.enrich_prims(self.opts.clone()), self.runner.clone(), self.helpers.clone(), ); - eval.add_extension(Rc::new(PreprocessorExtension::new())); + eval.add_extension(ppext); let res = eval.shrink_bodyform( &mut allocator, mdata.args.clone(), diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index ea71d1874..c735c5c53 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -961,3 +961,35 @@ fn test_double_constant_fail() { assert!(result.contains("not a number given to only-integers")); assert!(result.contains("\"hithere\"")); } + +#[test] +fn test_double_constant_pass_in_function() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/double-constant-pass-in-function.clsp".to_string(), + ]); + let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "(13)".to_string()]) + .trim() + .to_string(); + assert_eq!(result, "211"); +} + +#[test] +fn test_check_symbol_kinds_nested_if() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/strict-classify-expr-if.clsp".to_string(), + ]); + let result_1 = do_basic_brun(&vec!["brun".to_string(), result_prog.clone(), "(1)".to_string()]) + .trim() + .to_string(); + assert_eq!(result_1, "2"); + let result_0 = do_basic_brun(&vec!["brun".to_string(), result_prog, "(0)".to_string()]) + .trim() + .to_string(); + assert_eq!(result_0, "(q 1 2 3 4 4)"); +} diff --git a/src/tests/classic/stage_2.rs b/src/tests/classic/stage_2.rs index a83846b9f..b92b3d921 100644 --- a/src/tests/classic/stage_2.rs +++ b/src/tests/classic/stage_2.rs @@ -374,6 +374,9 @@ impl CompilerOpts for TestCompilerOptsPresentsOwnFiles { fn set_start_env(&self, _start_env: Option>) -> Rc { Rc::new(self.clone()) } + fn set_prim_map(&self, _prims: Rc, Rc>>) -> Rc { + Rc::new(self.clone()) + } fn read_new_file( &self, inc_from: String, diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 0eecaed3f..497b538b0 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -49,6 +49,7 @@ fn run_string_maybe_opt( Rc::new(HashMap::new()), Rc::new(x), sexp_args, + None, Some(TEST_TIMEOUT), ) .map_err(|e| match e { From 9d63e50694a91c528fc74b731e2540557903b857 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 30 May 2023 12:30:01 -0700 Subject: [PATCH 065/196] test files --- .../double-constant-pass-in-function.clsp | 26 +++++++++++++++++++ .../tests/strict/strict-classify-expr-if.clsp | 24 +++++++++++++++++ .../strict/strict-in-place-factorial.clsp | 6 +++++ 3 files changed, 56 insertions(+) create mode 100644 resources/tests/strict/double-constant-pass-in-function.clsp create mode 100644 resources/tests/strict/strict-classify-expr-if.clsp create mode 100644 resources/tests/strict/strict-in-place-factorial.clsp diff --git a/resources/tests/strict/double-constant-pass-in-function.clsp b/resources/tests/strict/double-constant-pass-in-function.clsp new file mode 100644 index 000000000..a3367039f --- /dev/null +++ b/resources/tests/strict/double-constant-pass-in-function.clsp @@ -0,0 +1,26 @@ +(mod (X) + (include *strict-cl-21*) + + ;; A macro-level function to pass through only real integers. + (defun pass-through-integers (X) + (if (not (number? X)) + (x "not a number given to only-integers" X) + X + ) + ) + + ;; A macro which at preprocessing time throws if the given argument + ;; wasn't a lexical integer. + (defmac only-integers (X) (pass-through-integers X)) + + ;; Note: when macro expanding, N is the N argument to the body of + ;; the double macro, not the integer literal, so we use the function + ;; version of pass-through-integers in the macro body. + (defmac double (N) (* 2 (pass-through-integers N))) + + ;; Here the macro form of only-integers can determine whether the + ;; double macro produced an integer or some other expression. + (defun F (N) (+ N (only-integers (double 99)))) + + (F X) + ) diff --git a/resources/tests/strict/strict-classify-expr-if.clsp b/resources/tests/strict/strict-classify-expr-if.clsp new file mode 100644 index 000000000..03288183d --- /dev/null +++ b/resources/tests/strict/strict-classify-expr-if.clsp @@ -0,0 +1,24 @@ +(mod (X) + (include *strict-cl-21*) + ;; Ensure macros can expand inside other macros when using advanced primitives. + (defmac classify-expr (G) + (if (number? G) + 1 + (if (symbol? G) + 2 + (if (string? G) + 3 + (if (l G) + 4 + 0 + ) + ) + ) + ) + ) + + (if X + (classify-expr X) + (list (classify-expr ()) (classify-expr 33) (classify-expr test) (classify-expr "foo") (classify-expr (* 3 2)) (classify-expr (list 1 2 3))) + ) + ) diff --git a/resources/tests/strict/strict-in-place-factorial.clsp b/resources/tests/strict/strict-in-place-factorial.clsp new file mode 100644 index 000000000..6b036beac --- /dev/null +++ b/resources/tests/strict/strict-in-place-factorial.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *strict-cl-21*) + (defmac factorial (N) + (if (> 2 N) 1 (qq (* (unquote N) (factorial (- N 1)))))) + (factorial 5) + ) From dc0dc627559ca7deb38999db137b2ce74dfa243e Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 30 May 2023 12:44:10 -0700 Subject: [PATCH 066/196] fmt + clippy --- src/compiler/clvm.rs | 33 ++++++++++++++++++++-------- src/compiler/evaluate.rs | 46 ++++++++++++++++++++++------------------ src/tests/classic/run.rs | 10 ++++++--- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/src/compiler/clvm.rs b/src/compiler/clvm.rs index a1e535532..a514a67c1 100644 --- a/src/compiler/clvm.rs +++ b/src/compiler/clvm.rs @@ -22,7 +22,12 @@ use crate::util::{number_from_u8, u8_from_number, Number}; /// Provide a way of intercepting and running new primitives. pub trait PrimOverride { - fn try_handle(&self, head: Rc, context: Rc, tail: Rc) -> Result>, RunFailure>; + fn try_handle( + &self, + head: Rc, + context: Rc, + tail: Rc, + ) -> Result>, RunFailure>; } /// An object which contains the state of a running CLVM program in a compact @@ -166,7 +171,15 @@ fn translate_head( Some(v) => Ok(Rc::new(v.with_loc(l.clone()))), }, SExp::Cons(_l, _a, nil) => match nil.borrow() { - SExp::Nil(_l1) => run(allocator, runner, prim_map, sexp.clone(), context, None, None), + SExp::Nil(_l1) => run( + allocator, + runner, + prim_map, + sexp.clone(), + context, + None, + None, + ), _ => Err(RunFailure::RunErr( sexp.loc(), format!("Unexpected head form in clvm {sexp}"), @@ -524,12 +537,8 @@ pub fn run_step( }; if let Some(ovr) = prim_override { - if let Some(res) = - ovr.try_handle(head.clone(), context.clone(), tail.clone())? - { - return Ok(RunStep::OpResult( - res.loc(), res.clone(), parent.clone() - )); + if let Some(res) = ovr.try_handle(head.clone(), context.clone(), tail.clone())? { + return Ok(RunStep::OpResult(res.loc(), res.clone(), parent.clone())); } } @@ -661,7 +670,13 @@ pub fn run( } } iters += 1; - step = run_step(allocator, runner.clone(), prim_map.clone(), &step, prim_override.clone())?; + step = run_step( + allocator, + runner.clone(), + prim_map.clone(), + &step, + prim_override, + )?; if let RunStep::Done(_, x) = step { return Ok(x); } diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index d4142a0b2..033799b2b 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -9,7 +9,7 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::{PrimOverride, run}; +use crate::compiler::clvm::{run, PrimOverride}; use crate::compiler::codegen::codegen; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ @@ -136,42 +136,46 @@ pub struct Evaluator { fn compile_to_run_err(e: CompileErr) -> RunFailure { match e { - CompileErr(l, e) => { - RunFailure::RunErr(l.clone(), e.clone()) - } + CompileErr(l, e) => RunFailure::RunErr(l, e), } } impl PrimOverride for Evaluator { - fn try_handle(&self, head: Rc, _context: Rc, tail: Rc) -> Result>, RunFailure> { - let have_args: Vec> = - if let Some(args_list) = tail - .proper_list() { - args_list - .iter() - .map(|e| Rc::new(BodyForm::Quoted(e.clone()))) - .collect() - } else { - return Ok(None); - }; + fn try_handle( + &self, + head: Rc, + _context: Rc, + tail: Rc, + ) -> Result>, RunFailure> { + let have_args: Vec> = if let Some(args_list) = tail.proper_list() { + args_list + .iter() + .map(|e| Rc::new(BodyForm::Quoted(e.clone()))) + .collect() + } else { + return Ok(None); + }; if let SExp::Atom(hl, head_atom) = head.borrow() { - let mut call_args = - vec![Rc::new(BodyForm::Value(SExp::Atom(hl.clone(), head_atom.clone())))]; + let mut call_args = vec![Rc::new(BodyForm::Value(SExp::Atom( + hl.clone(), + head_atom.clone(), + )))]; call_args.append(&mut have_args.clone()); let call_form = Rc::new(BodyForm::Call(head.loc(), call_args)); for x in self.extensions.iter() { - if let Some(res) = - x.try_eval( + if let Some(res) = x + .try_eval( self, Rc::new(SExp::Nil(head.loc())), &HashMap::new(), &head.loc(), - &head_atom, + head_atom, &have_args, call_form.clone(), - ).map_err(compile_to_run_err)? + ) + .map_err(compile_to_run_err)? { return dequote(head.loc(), res) .map_err(compile_to_run_err) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index c735c5c53..1d48fa188 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -984,9 +984,13 @@ fn test_check_symbol_kinds_nested_if() { "resources/tests/strict".to_string(), "resources/tests/strict/strict-classify-expr-if.clsp".to_string(), ]); - let result_1 = do_basic_brun(&vec!["brun".to_string(), result_prog.clone(), "(1)".to_string()]) - .trim() - .to_string(); + let result_1 = do_basic_brun(&vec![ + "brun".to_string(), + result_prog.clone(), + "(1)".to_string(), + ]) + .trim() + .to_string(); assert_eq!(result_1, "2"); let result_0 = do_basic_brun(&vec!["brun".to_string(), result_prog, "(0)".to_string()]) .trim() From f8b665d8f88de3cee4e1d5dcce8f0d6ec8807789 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 1 Jun 2023 17:44:06 -0700 Subject: [PATCH 067/196] Make sure we grab the arguments of the lambda we're evaluating so code generation on behalf of (com ...) can function properly --- src/compiler/evaluate.rs | 2 +- src/tests/compiler/repl.rs | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 64a8e3474..bbf37bec7 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -745,7 +745,7 @@ impl<'info> Evaluator { self.shrink_bodyform_visited( allocator, visited, - prog_args, + lapply.lambda.args.clone(), &lambda_env, lapply.body.clone(), only_inline, diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index 65b384c62..18c655a59 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -344,3 +344,49 @@ fn test_lambda_eval_5() { "(q . 13)" ); } + +#[test] +fn test_lambda_eval_6() { + assert_eq!( + test_repl_outcome(vec![ + indoc!{" +(defun visit-atoms (fn acc mask path pattern) + (if (l pattern) + (visit-atoms + fn + (visit-atoms fn acc (* 2 mask) path (f pattern)) + (* 2 mask) + (logior mask path) + (r pattern) + ) + + (a fn (list acc (logior path mask) pattern)) + ) + ) +"}, + indoc!{" + (defun if-match (match) + (c 1 + (visit-atoms + (lambda (cb path pat) + (if (l pat) + (list cb \"A\") ;; Unbound use of cb + (list cb \"B\") + ) + ) + () + 1 + 0 + match + ) + ) + ) + +"}, + "(if-match (q test \"test\" t1 (t2 . t3)))" + ]) + .unwrap() + .unwrap(), + "(q 1 (((((() B) B) B) B) B) B)" + ); +} From 8b194782dc83c49265a1ad9439d6e0c118d558f4 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 1 Jun 2023 17:45:12 -0700 Subject: [PATCH 068/196] fmt + clippy --- src/compiler/evaluate.rs | 2 +- src/tests/compiler/repl.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index bbf37bec7..8455ca014 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -726,7 +726,7 @@ impl<'info> Evaluator { let reified_captures = self.shrink_bodyform_visited( allocator, visited, - prog_args.clone(), + prog_args, env, lapply.lambda.captures.clone(), only_inline, diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index 18c655a59..9280bdd02 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -349,7 +349,7 @@ fn test_lambda_eval_5() { fn test_lambda_eval_6() { assert_eq!( test_repl_outcome(vec![ - indoc!{" + indoc! {" (defun visit-atoms (fn acc mask path pattern) (if (l pattern) (visit-atoms @@ -364,7 +364,7 @@ fn test_lambda_eval_6() { ) ) "}, - indoc!{" + indoc! {" (defun if-match (match) (c 1 (visit-atoms @@ -385,8 +385,8 @@ fn test_lambda_eval_6() { "}, "(if-match (q test \"test\" t1 (t2 . t3)))" ]) - .unwrap() - .unwrap(), + .unwrap() + .unwrap(), "(q 1 (((((() B) B) B) B) B) B)" ); } From 35720bd643f61ab511d45531283bb60da591ccab Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 1 Jun 2023 19:09:40 -0700 Subject: [PATCH 069/196] Fixes bug which was clobbering the numeric names of operators when going into com --- src/compiler/preprocessor/macros.rs | 5 ++++- src/tests/compiler/preprocessor.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 6d6375d2c..caac2530b 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -780,7 +780,10 @@ impl PreprocessorExtension { let srcloc = Srcloc::start("*defmac*"); for (f, _) in self.extfuns.iter() { - new_prim_map_cloned.insert(f.clone(), Rc::new(SExp::Atom(srcloc.clone(), f.clone()))); + if !new_prim_map_cloned.contains_key(f) { + new_prim_map_cloned + .insert(f.clone(), Rc::new(SExp::Atom(srcloc.clone(), f.clone()))); + } } opts.set_prim_map(Rc::new(new_prim_map_cloned)) diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 1d8ab82b9..e55d10b49 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -531,3 +531,17 @@ fn test_preprocess_basic_list() { .expect("should preprocess"); assert_eq!(pp[pp.len() - 1].to_string(), "(4 1 (4 2 (4 3 ())))"); } + +#[test] +fn test_preprocess_expansion_makes_numeric_operators() { + let prog = indoc! {" + (mod () + (include *strict-cl-21*) + (defmac G () (com (4 \"test\" ()))) + (G) + ) + "} + .to_string(); + let res = run_string(&prog, &"()".to_string()).unwrap(); + assert_eq!(res.to_string(), "(\"test\")"); +} From 7e05c1dd06f1495eb0d772e7d2fe2c23764b9c90 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 1 Jun 2023 19:32:24 -0700 Subject: [PATCH 070/196] clippy --- src/compiler/clvm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/clvm.rs b/src/compiler/clvm.rs index a514a67c1..9a0261575 100644 --- a/src/compiler/clvm.rs +++ b/src/compiler/clvm.rs @@ -206,7 +206,7 @@ fn eval_args( return Ok(RunStep::Op( head, context_, - sexp.clone(), + sexp, Some(eval_list), parent, )); From 8689af2a6f393e5b2e350d48baf5c14c48e83254 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 1 Jun 2023 19:36:59 -0700 Subject: [PATCH 071/196] fmt --- src/compiler/clvm.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/compiler/clvm.rs b/src/compiler/clvm.rs index 9a0261575..f5b8bb0b9 100644 --- a/src/compiler/clvm.rs +++ b/src/compiler/clvm.rs @@ -203,13 +203,7 @@ fn eval_args( loop { match sexp.borrow() { SExp::Nil(_l) => { - return Ok(RunStep::Op( - head, - context_, - sexp, - Some(eval_list), - parent, - )); + return Ok(RunStep::Op(head, context_, sexp, Some(eval_list), parent)); } SExp::Cons(_l, a, b) => { eval_list.push(a.clone()); From 9e4979f7595b9262b03b676635241d5bd3e7261e Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 13 Jun 2023 10:45:45 -0700 Subject: [PATCH 072/196] Fix not doing full preprocessing on include file contents in strict mode --- src/compiler/preprocessor/mod.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 1e935d30a..b1b2632c2 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -23,6 +23,7 @@ struct Preprocessor { opts: Rc, runner: Rc, helpers: Vec, + strict: bool, } /* @@ -55,6 +56,7 @@ impl Preprocessor { opts: opts.clone(), runner, helpers: Vec::new(), + strict: opts.dialect().strict, } } @@ -69,7 +71,7 @@ impl Preprocessor { // Because we're also subsequently returning CompileErr later in the pipe, // this needs an explicit err map. - parse_sexp(start_of_file.clone(), content.bytes()) + let parsed: Vec> = parse_sexp(start_of_file.clone(), content.bytes()) .err_into() .and_then(|x| match x[0].proper_list() { None => Err(CompileErr( @@ -77,7 +79,20 @@ impl Preprocessor { "Includes should contain a list of forms".to_string(), )), Some(v) => Ok(v.iter().map(|x| Rc::new(x.clone())).collect()), - }) + })?; + + if self.strict { + let mut result = Vec::new(); + for p in parsed.into_iter() { + if let Some(res) = self.expand_macros(p.clone(), true)? { + result.push(res); + } + } + + Ok(result) + } else { + Ok(parsed) + } } fn recurse_dependencies( From fd9c877400983208a35ae6b215cbd9e5363b9948 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 16 Jun 2023 15:59:52 -0700 Subject: [PATCH 073/196] Fix bug in strict preprocessor and add test --- src/compiler/preprocessor/mod.rs | 2 +- src/tests/compiler/preprocessor.rs | 66 ++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index b1b2632c2..8107ea8c6 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -150,7 +150,7 @@ impl Preprocessor { let first_expanded = self.expand_macros(f.clone(), true)?; let rest_expanded = self.expand_macros(r.clone(), false)?; let new_self = match (first_expanded, rest_expanded) { - (None, None) => None, + (None, None) => Some(body.clone()), (Some(f), None) => Some(Rc::new(SExp::Cons(l.clone(), f, r.clone()))), (None, Some(r)) => Some(Rc::new(SExp::Cons(l.clone(), f.clone(), r))), (Some(f), Some(r)) => Some(Rc::new(SExp::Cons(l.clone(), f, r))), diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index e55d10b49..0546acc70 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -545,3 +545,69 @@ fn test_preprocess_expansion_makes_numeric_operators() { let res = run_string(&prog, &"()".to_string()).unwrap(); assert_eq!(res.to_string(), "(\"test\")"); } + +#[test] +fn test_preprocessor_tours_includes_properly() { + let prog = indoc! {" + ( ;; Note: preprocessing is run in the list of the body forms. + (include *standard-cl-23*) + (include condition_codes.clvm) + (include curry-and-treehash.clinc) + () + ) + "}.to_string(); + let pname = "*test*"; + let opts: Rc = Rc::new(DefaultCompilerOpts::new(pname)) + .set_search_paths(&["resources/tests".to_string()]) + .set_dialect(AcceptedDialect { + stepping: Some(23), + strict: true + }); + let parsed = parse_sexp(Srcloc::start(pname), prog.bytes()).expect("should parse"); + let mut includes = Vec::new(); + let res = preprocess(opts, &mut includes, parsed[0].clone()).expect("should preprocess"); + let expected_lines = &[ + "(defmac if (A B C) (qq (a (i (unquote A) (com (unquote B)) (com (unquote C))) @)))", + "(defun __chia__compile-list (args) (a (i args (com (c 4 (c (f args) (c (__chia__compile-list (r args)) ())))) (com ())) @))", + "(defmac list ARGS (__chia__compile-list ARGS))", + "(defun-inline / (A B) (f (divmod A B)))", + "(defun-inline c* (A B) (c A B))", + "(defun-inline a* (A B) (a A B))", + "(defun-inline coerce (X) : (Any -> Any) X)", + "(defun-inline explode (X) : (forall a ((Exec a) -> a)) X)", + "(defun-inline bless (X) : (forall a ((Pair a Unit) -> (Exec a))) (coerce X))", + "(defun-inline lift (X V) : (forall a (forall b ((Pair (Exec a) (Pair b Unit)) -> (Exec (Pair a b))))) (coerce X))", + "(defun-inline unlift (X) : (forall a (forall b ((Pair (Exec (Pair a b)) Unit) -> (Exec b)))) (coerce X))", + "(defconstant *chialisp-version* 23)", + "(defconstant AGG_SIG_UNSAFE 49)", + "(defconstant AGG_SIG_ME 50)", + "(defconstant CREATE_COIN 51)", + "(defconstant RESERVE_FEE 52)", + "(defconstant CREATE_COIN_ANNOUNCEMENT 60)", + "(defconstant ASSERT_COIN_ANNOUNCEMENT 61)", + "(defconstant CREATE_PUZZLE_ANNOUNCEMENT 62)", + "(defconstant ASSERT_PUZZLE_ANNOUNCEMENT 63)", + "(defconstant ASSERT_MY_COIN_ID 70)", + "(defconstant ASSERT_MY_PARENT_ID 71)", + "(defconstant ASSERT_MY_PUZZLEHASH 72)", + "(defconstant ASSERT_MY_AMOUNT 73)", + "(defconstant ASSERT_SECONDS_RELATIVE 80)", + "(defconstant ASSERT_SECONDS_ABSOLUTE 81)", + "(defconstant ASSERT_HEIGHT_RELATIVE 82)", + "(defconstant ASSERT_HEIGHT_ABSOLUTE 83)", + "(defconstant ONE 1)", + "(defconstant TWO 2)", + "(defconstant A_KW 2)", + "(defconstant Q_KW 1)", + "(defconstant C_KW 4)", + "(defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) (sha256 TWO (sha256 ONE C_KW) (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) parameter-hash) (sha256 TWO environment-hash (sha256 ONE ())))))", + "(defun build-curry-list (reversed-curry-parameter-hashes environment-hash) (a (i reversed-curry-parameter-hashes (com (build-curry-list (r reversed-curry-parameter-hashes) (update-hash-for-parameter-hash (f reversed-curry-parameter-hashes) environment-hash))) (com environment-hash)) @))", + "(defun-inline tree-hash-of-apply (function-hash environment-hash) (sha256 TWO (sha256 ONE A_KW) (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) function-hash) (sha256 TWO environment-hash (sha256 ONE ())))))", + "(defun puzzle-hash-of-curried-function (function-hash . reversed-curry-parameter-hashes) (tree-hash-of-apply function-hash (build-curry-list reversed-curry-parameter-hashes (sha256 ONE ONE))))", + "()", + ]; + for (i, r) in res.iter().enumerate() { + assert_eq!(r.to_string(), expected_lines[i]); + } + assert_eq!(res.len(), expected_lines.len()); +} From 1ec5d4cbfcde63fdf492039b70799c3860a79181 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 16 Jun 2023 16:00:16 -0700 Subject: [PATCH 074/196] fmt --- src/tests/compiler/preprocessor.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 0546acc70..07e9838ba 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -555,13 +555,14 @@ fn test_preprocessor_tours_includes_properly() { (include curry-and-treehash.clinc) () ) - "}.to_string(); + "} + .to_string(); let pname = "*test*"; let opts: Rc = Rc::new(DefaultCompilerOpts::new(pname)) .set_search_paths(&["resources/tests".to_string()]) .set_dialect(AcceptedDialect { stepping: Some(23), - strict: true + strict: true, }); let parsed = parse_sexp(Srcloc::start(pname), prog.bytes()).expect("should parse"); let mut includes = Vec::new(); From 4b7b0bfc79a882ef571116ca5db5cefb7d4c75fc Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 16 Jun 2023 20:01:08 -0700 Subject: [PATCH 075/196] Add -E preprocessing mode --- src/classic/clvm_tools/cmds.rs | 57 ++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index f8c2d7549..57c000622 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -1,5 +1,6 @@ use core::cell::RefCell; +use std::borrow::Borrow; use std::collections::{BTreeMap, HashMap}; use std::fs; use std::io; @@ -51,6 +52,7 @@ use crate::compiler::cldb::{hex_to_modern_sexp, CldbNoOverride, CldbRun, CldbRun use crate::compiler::cldb_hierarchy::{HierarchialRunner, HierarchialStepResult, RunPurpose}; use crate::compiler::clvm::start_step; use crate::compiler::compiler::{compile_file, run_optimizer, DefaultCompilerOpts}; +use crate::compiler::frontend::frontend; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::debug::build_symbol_table_mut; use crate::compiler::dialect::detect_modern; @@ -773,6 +775,47 @@ fn fix_log( } } +fn perform_preprocessing(stdout: &mut Stream, opts: Rc, input_file: &str, program_text: &str) -> Result<(), CompileErr> { + let srcloc = Srcloc::start(input_file); + let parsed = parse_sexp(srcloc.clone(), program_text.bytes())?; + let stepping_form_text = + match opts.dialect().stepping { + Some(21) => Some("(include *strict-cl-21*)".to_string()), + Some(n) => Some(format!("(include *standard-cl-{n}*)")), + _ => None + }; + let frontend = frontend(opts, &parsed)?; + let fe_sexp = frontend.to_sexp(); + let with_stepping = + if let Some(s) = stepping_form_text { + let parsed_stepping_form = parse_sexp(srcloc.clone(), s.bytes())?; + if let sexp::SExp::Cons(_, a, rest) = fe_sexp.clone().borrow() { + Rc::new(sexp::SExp::Cons( + srcloc.clone(), + a.clone(), + Rc::new(sexp::SExp::Cons( + srcloc.clone(), + parsed_stepping_form[0].clone(), + rest.clone() + )) + )) + } else { + fe_sexp.clone() + } + } else { + fe_sexp.clone() + }; + + let whole_mod = sexp::SExp::Cons( + srcloc.clone(), + Rc::new(sexp::SExp::Atom(srcloc.clone(), b"mod".to_vec())), + with_stepping + ); + + stdout.write_str(&format!("{}", whole_mod)); + Ok(()) +} + pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, default_stage: u32) { let props = TArgumentParserProps { description: "Execute a clvm script.".to_string(), @@ -917,6 +960,12 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .set_action(TArgOptionAction::StoreTrue) .set_help("For modern dialects, don't treat unknown names as constants".to_string()), ); + parser.add_argument( + vec!["-E".to_string(), "--preprocess".to_string()], + Argument::new() + .set_action(TArgOptionAction::StoreTrue) + .set_help("Perform strict mode preprocessing and show the result".to_string()), + ); if tool_name == "run" { parser.add_argument( @@ -1204,6 +1253,14 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .set_frontend_opt(stepping > 21); let mut symbol_table = HashMap::new(); + // Short circuit preprocessing display. + if let Some(_) = parsed_args.get("preprocess") { + if let Err(e) = perform_preprocessing(stdout, opts, &use_filename, &input_program) { + stdout.write_str(&format!("{}: {}", e.0, e.1)); + } + return; + } + let unopt_res = compile_file( &mut allocator, runner.clone(), From 22316dfd943a5138162cdbcf8401922f3fda956c Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 16 Jun 2023 20:03:01 -0700 Subject: [PATCH 076/196] fmt + clippy --- src/classic/clvm_tools/cmds.rs | 57 ++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 57c000622..b1e3ef7e6 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -52,10 +52,10 @@ use crate::compiler::cldb::{hex_to_modern_sexp, CldbNoOverride, CldbRun, CldbRun use crate::compiler::cldb_hierarchy::{HierarchialRunner, HierarchialStepResult, RunPurpose}; use crate::compiler::clvm::start_step; use crate::compiler::compiler::{compile_file, run_optimizer, DefaultCompilerOpts}; -use crate::compiler::frontend::frontend; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::debug::build_symbol_table_mut; use crate::compiler::dialect::detect_modern; +use crate::compiler::frontend::frontend; use crate::compiler::preprocessor::gather_dependencies; use crate::compiler::prims; use crate::compiler::runtypes::RunFailure; @@ -775,41 +775,44 @@ fn fix_log( } } -fn perform_preprocessing(stdout: &mut Stream, opts: Rc, input_file: &str, program_text: &str) -> Result<(), CompileErr> { +fn perform_preprocessing( + stdout: &mut Stream, + opts: Rc, + input_file: &str, + program_text: &str, +) -> Result<(), CompileErr> { let srcloc = Srcloc::start(input_file); let parsed = parse_sexp(srcloc.clone(), program_text.bytes())?; - let stepping_form_text = - match opts.dialect().stepping { - Some(21) => Some("(include *strict-cl-21*)".to_string()), - Some(n) => Some(format!("(include *standard-cl-{n}*)")), - _ => None - }; + let stepping_form_text = match opts.dialect().stepping { + Some(21) => Some("(include *strict-cl-21*)".to_string()), + Some(n) => Some(format!("(include *standard-cl-{n}*)")), + _ => None, + }; let frontend = frontend(opts, &parsed)?; let fe_sexp = frontend.to_sexp(); - let with_stepping = - if let Some(s) = stepping_form_text { - let parsed_stepping_form = parse_sexp(srcloc.clone(), s.bytes())?; - if let sexp::SExp::Cons(_, a, rest) = fe_sexp.clone().borrow() { + let with_stepping = if let Some(s) = stepping_form_text { + let parsed_stepping_form = parse_sexp(srcloc.clone(), s.bytes())?; + if let sexp::SExp::Cons(_, a, rest) = fe_sexp.borrow() { + Rc::new(sexp::SExp::Cons( + srcloc.clone(), + a.clone(), Rc::new(sexp::SExp::Cons( srcloc.clone(), - a.clone(), - Rc::new(sexp::SExp::Cons( - srcloc.clone(), - parsed_stepping_form[0].clone(), - rest.clone() - )) - )) - } else { - fe_sexp.clone() - } + parsed_stepping_form[0].clone(), + rest.clone(), + )), + )) } else { - fe_sexp.clone() - }; + fe_sexp + } + } else { + fe_sexp + }; let whole_mod = sexp::SExp::Cons( srcloc.clone(), - Rc::new(sexp::SExp::Atom(srcloc.clone(), b"mod".to_vec())), - with_stepping + Rc::new(sexp::SExp::Atom(srcloc, b"mod".to_vec())), + with_stepping, ); stdout.write_str(&format!("{}", whole_mod)); @@ -1254,7 +1257,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let mut symbol_table = HashMap::new(); // Short circuit preprocessing display. - if let Some(_) = parsed_args.get("preprocess") { + if parsed_args.get("preprocess").is_some() { if let Err(e) = perform_preprocessing(stdout, opts, &use_filename, &input_program) { stdout.write_str(&format!("{}: {}", e.0, e.1)); } From 06733ded72b0964e2626d612b7a1c1870921b06d Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 16 Jun 2023 20:31:46 -0700 Subject: [PATCH 077/196] Basic smoke test of strict style preprocessing with -E --- resources/tests/strict/defmac_if_smoke.clsp | 8 +++++++ resources/tests/strict/defmac_simple_if.clib | 3 +++ src/tests/classic/run.rs | 25 ++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 resources/tests/strict/defmac_if_smoke.clsp create mode 100644 resources/tests/strict/defmac_simple_if.clib diff --git a/resources/tests/strict/defmac_if_smoke.clsp b/resources/tests/strict/defmac_if_smoke.clsp new file mode 100644 index 000000000..d3baf7cca --- /dev/null +++ b/resources/tests/strict/defmac_if_smoke.clsp @@ -0,0 +1,8 @@ +(mod () + (include *strict-cl-21*) + + (include defmac_simple_if.clib) + + (if_ t1 t2 t3) + ) + \ No newline at end of file diff --git a/resources/tests/strict/defmac_simple_if.clib b/resources/tests/strict/defmac_simple_if.clib new file mode 100644 index 000000000..32655f11f --- /dev/null +++ b/resources/tests/strict/defmac_simple_if.clib @@ -0,0 +1,3 @@ +( + (defmac if_ (C T E) (qq (if (unquote C) (unquote T) (unquote E)))) +) \ No newline at end of file diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 1d48fa188..c081baa74 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -997,3 +997,28 @@ fn test_check_symbol_kinds_nested_if() { .to_string(); assert_eq!(result_0, "(q 1 2 3 4 4)"); } + +// Note: this program is intentionally made to properly preprocess but trigger +// an error in strict compilation as a demonstration and test that the preprocessor +// is a mechanically separate step from compilation. Separating them like this +// has the advantage that you can emit preprocessed compiler input on its own +// and also that it internally untangles the stages and makes compilation simpler. +#[test] +fn test_defmac_if_smoke_preprocess() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "-E".to_string(), + "resources/tests/strict/defmac_if_smoke.clsp".to_string(), + ]); + assert_eq!( + result_prog, + "(mod () (include *strict-cl-21*) (a (i t1 (com t2) (com t3)) @))" + ); + let result2 = do_basic_run(&vec!["run".to_string(), result_prog]); + assert!(result2.contains("Unbound use")); + // Ensure that we're identifying one of the actually misused variables, but + // do not make a claim about which one is identified first. + assert!(result2.contains("of t1") || result2.contains("of t2") || result2.contains("of t3")); +} From 93699a7a1141daad22956ef2a07eb193e36360cc Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 16 Jun 2023 21:03:43 -0700 Subject: [PATCH 078/196] Add some more defmac tests. --- resources/tests/strict/assert.clsp | 11 +++++++ resources/tests/strict/defmac_assert.clib | 10 +++++++ src/tests/classic/run.rs | 35 +++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 resources/tests/strict/assert.clsp create mode 100644 resources/tests/strict/defmac_assert.clib diff --git a/resources/tests/strict/assert.clsp b/resources/tests/strict/assert.clsp new file mode 100644 index 000000000..cf9a3801e --- /dev/null +++ b/resources/tests/strict/assert.clsp @@ -0,0 +1,11 @@ +(mod (A) + (include *strict-cl-21*) + + (include defmac_assert.clib) + + (assert + 1 + A + 13 + ) + ) diff --git a/resources/tests/strict/defmac_assert.clib b/resources/tests/strict/defmac_assert.clib new file mode 100644 index 000000000..1dccb32c8 --- /dev/null +++ b/resources/tests/strict/defmac_assert.clib @@ -0,0 +1,10 @@ +( + (defun assert_ (items) + (if (r items) + (qq (if (unquote (f items)) (unquote (assert_ (r items))) (x))) + (f items) + ) + ) + + (defmac assert items (assert_ items)) +) \ No newline at end of file diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index c081baa74..af9e68be1 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1022,3 +1022,38 @@ fn test_defmac_if_smoke_preprocess() { // do not make a claim about which one is identified first. assert!(result2.contains("of t1") || result2.contains("of t2") || result2.contains("of t3")); } + +#[test] +fn test_defmac_assert_smoke_preprocess() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "-E".to_string(), + "resources/tests/strict/assert.clsp".to_string(), + ]); + assert_eq!( + result_prog, + "(mod (A) (include *strict-cl-21*) (a (i 1 (com (a (i A (com 13) (com (x))) @)) (com (x))) @))" + ); + let result_after_preproc = do_basic_run(&vec!["run".to_string(), result_prog]); + let result_with_preproc = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/assert.clsp".to_string(), + ]); + assert_eq!(result_after_preproc, result_with_preproc); + let run_result_true = do_basic_brun(&vec![ + "brun".to_string(), + result_with_preproc.clone(), + "(15)".to_string() + ]); + assert_eq!(run_result_true.trim(), "13"); + let run_result_false = do_basic_brun(&vec![ + "brun".to_string(), + result_with_preproc.clone(), + "(0)".to_string() + ]); + assert_eq!(run_result_false.trim(), "FAIL: clvm raise ()"); +} From 6bed699ca52646f9a7b571c383f8bee4cc75c8f7 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 16 Jun 2023 21:04:11 -0700 Subject: [PATCH 079/196] fmt --- src/tests/classic/run.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index af9e68be1..f9b744781 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1047,13 +1047,13 @@ fn test_defmac_assert_smoke_preprocess() { let run_result_true = do_basic_brun(&vec![ "brun".to_string(), result_with_preproc.clone(), - "(15)".to_string() + "(15)".to_string(), ]); assert_eq!(run_result_true.trim(), "13"); let run_result_false = do_basic_brun(&vec![ "brun".to_string(), result_with_preproc.clone(), - "(0)".to_string() + "(0)".to_string(), ]); assert_eq!(run_result_false.trim(), "FAIL: clvm raise ()"); } From 23658399acce14b91026fe4a1d475af3f7ef4257 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 26 Jun 2023 15:56:33 -0700 Subject: [PATCH 080/196] Improve macros by renaming function arguments before interning them, allowing us to find a few more problems earlier. This revealed an old bug in the renamer which is corrected. It would always have broken potentially valid programs, so won't break anything existing. --- src/compiler/preprocessor/mod.rs | 5 +++-- src/compiler/rename.rs | 11 +++++++++-- src/tests/compiler/preprocessor.rs | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 8107ea8c6..d150ff024 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -13,6 +13,7 @@ use crate::compiler::dialect::KNOWN_DIALECTS; use crate::compiler::evaluate::{create_argument_captures, dequote, ArgInputs, Evaluator}; use crate::compiler::frontend::compile_helperform; use crate::compiler::preprocessor::macros::PreprocessorExtension; +use crate::compiler::rename::rename_args_helperform; use crate::compiler::sexp::{ decode_string, enlist, parse_sexp, Atom, NodeSel, SExp, SelectNode, ThisNode, }; @@ -255,7 +256,7 @@ impl Preprocessor { )), )); if let Some(helper) = compile_helperform(self.opts.clone(), target_defun)? { - self.add_helper(helper); + self.add_helper(rename_args_helperform(&helper)); } else { return Err(CompileErr( definition.loc(), @@ -263,7 +264,7 @@ impl Preprocessor { )); } } else if let Some(helper) = compile_helperform(self.opts.clone(), definition)? { - self.add_helper(helper); + self.add_helper(rename_args_helperform(&helper)); } } } diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 73f75db1a..2673e3946 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -164,7 +164,14 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B BodyForm::Call(l, vs) => { let new_vs = vs .iter() - .map(|x| Rc::new(rename_in_bodyform(namemap, x.clone()))) + .enumerate() + .map(|(i,x)| { + if i == 0 { + x.clone() + } else { + Rc::new(rename_in_bodyform(namemap, x.clone())) + } + }) .collect(); BodyForm::Call(l.clone(), new_vs) } @@ -289,7 +296,7 @@ fn rename_in_helperform(namemap: &HashMap, Vec>, h: &HelperForm) -> } } -fn rename_args_helperform(h: &HelperForm) -> HelperForm { +pub fn rename_args_helperform(h: &HelperForm) -> HelperForm { match h { HelperForm::Defconstant(defc) => HelperForm::Defconstant(DefconstData { loc: defc.loc.clone(), diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 07e9838ba..9d8947227 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -455,7 +455,7 @@ fn test_defmac_string_to_number_0() { let prog = indoc! {" (mod (X_7) (defmac add-n-to (X) - (let + (let* ((stringified (symbol->string X)) (slen (string-length stringified)) (number-part (substring stringified (- slen 1) slen)) From e2e4df25dd009b1422fb89080bcb020f7b4888c0 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 26 Jun 2023 15:58:20 -0700 Subject: [PATCH 081/196] fmt --- src/compiler/rename.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 2673e3946..8c7a51ec4 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -165,7 +165,7 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B let new_vs = vs .iter() .enumerate() - .map(|(i,x)| { + .map(|(i, x)| { if i == 0 { x.clone() } else { From 4d7bea2eb562d633f123743b0a392cfea3510fa3 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 26 Jun 2023 16:11:44 -0700 Subject: [PATCH 082/196] Add pinning of wasm-pack --- .github/workflows/npm-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index d8424af7c..395a02866 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -30,7 +30,7 @@ jobs: components: rustfmt, clippy - name: install wasm-pack - run: cargo install wasm-pack + run: cargo install --version 0.11.1 wasm-pack - name: wasm-pack build and pack run: wasm-pack build --release --target=nodejs wasm && wasm-pack pack wasm From 91799907689d2de874e7b760fb98705031bec38b Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 3 Aug 2023 09:29:47 -0700 Subject: [PATCH 083/196] fmt + clippy --- src/classic/clvm/casts.rs | 2 +- src/classic/clvm/sexp.rs | 12 ++++++------ src/classic/clvm_tools/binutils.rs | 8 ++++---- src/classic/clvm_tools/cmds.rs | 11 +++++++---- src/classic/clvm_tools/stages/stage_2/compile.rs | 4 ++-- src/classic/clvm_tools/stages/stage_2/inline.rs | 2 +- src/classic/clvm_tools/stages/stage_2/module.rs | 2 +- src/classic/clvm_tools/stages/stage_2/operators.rs | 4 ++-- src/classic/clvm_tools/stages/stage_2/optimize.rs | 2 +- src/compiler/dialect.rs | 7 +++++-- src/compiler/evaluate.rs | 3 ++- src/compiler/inline.rs | 2 +- src/compiler/repl.rs | 2 +- 13 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/classic/clvm/casts.rs b/src/classic/clvm/casts.rs index 4aeeab5ec..de10c7190 100644 --- a/src/classic/clvm/casts.rs +++ b/src/classic/clvm/casts.rs @@ -13,7 +13,7 @@ pub struct TConvertOption { } pub fn int_from_bytes( - allocator: &mut Allocator, + allocator: &Allocator, b: Bytes, option: Option, ) -> Result { diff --git a/src/classic/clvm/sexp.rs b/src/classic/clvm/sexp.rs index ef730eedd..4757014b4 100644 --- a/src/classic/clvm/sexp.rs +++ b/src/classic/clvm/sexp.rs @@ -224,7 +224,7 @@ pub fn sexp_as_bin(allocator: &mut Allocator, sexp: NodePtr) -> Bytes { f.get_value() } -pub fn bool_sexp(allocator: &mut Allocator, b: bool) -> NodePtr { +pub fn bool_sexp(allocator: &Allocator, b: bool) -> NodePtr { if b { allocator.one() } else { @@ -332,7 +332,7 @@ pub fn bool_sexp(allocator: &mut Allocator, b: bool) -> NodePtr { // ; // } -pub fn non_nil(allocator: &mut Allocator, sexp: NodePtr) -> bool { +pub fn non_nil(allocator: &Allocator, sexp: NodePtr) -> bool { match allocator.sexp(sexp) { SExp::Pair(_, _) => true, // sexp is the only node in scope, was !is_empty @@ -340,28 +340,28 @@ pub fn non_nil(allocator: &mut Allocator, sexp: NodePtr) -> bool { } } -pub fn first(allocator: &mut Allocator, sexp: NodePtr) -> Result { +pub fn first(allocator: &Allocator, sexp: NodePtr) -> Result { match allocator.sexp(sexp) { SExp::Pair(f, _) => Ok(f), _ => Err(EvalErr(sexp, "first of non-cons".to_string())), } } -pub fn rest(allocator: &mut Allocator, sexp: NodePtr) -> Result { +pub fn rest(allocator: &Allocator, sexp: NodePtr) -> Result { match allocator.sexp(sexp) { SExp::Pair(_, r) => Ok(r), _ => Err(EvalErr(sexp, "rest of non-cons".to_string())), } } -pub fn atom(allocator: &mut Allocator, sexp: NodePtr) -> Result, EvalErr> { +pub fn atom(allocator: &Allocator, sexp: NodePtr) -> Result, EvalErr> { match allocator.sexp(sexp) { SExp::Atom() => Ok(allocator.atom(sexp).to_vec()), // only sexp in scope _ => Err(EvalErr(sexp, "not an atom".to_string())), } } -pub fn proper_list(allocator: &mut Allocator, sexp: NodePtr, store: bool) -> Option> { +pub fn proper_list(allocator: &Allocator, sexp: NodePtr, store: bool) -> Option> { let mut args = vec![]; let mut args_sexp = sexp; loop { diff --git a/src/classic/clvm_tools/binutils.rs b/src/classic/clvm_tools/binutils.rs index deac313cc..9fc1e4916 100644 --- a/src/classic/clvm_tools/binutils.rs +++ b/src/classic/clvm_tools/binutils.rs @@ -111,7 +111,7 @@ pub fn ir_for_atom( * (2 2 (2) (2 3 4)) => (a 2 (a) (a 3 4)) */ pub fn disassemble_to_ir_with_kw( - allocator: &mut Allocator, + allocator: &Allocator, sexp: NodePtr, keyword_from_atom: &Record, String>, mut allow_keyword: bool, @@ -136,7 +136,7 @@ pub fn disassemble_to_ir_with_kw( } pub fn disassemble_with_kw( - allocator: &mut Allocator, + allocator: &Allocator, sexp: NodePtr, keyword_from_atom: &Record, String>, ) -> String { @@ -145,8 +145,8 @@ pub fn disassemble_with_kw( write_ir(Rc::new(symbols)) } -pub fn disassemble(allocator: &mut Allocator, sexp: NodePtr) -> String { - return disassemble_with_kw(allocator, sexp, keyword_from_atom()); +pub fn disassemble(allocator: &Allocator, sexp: NodePtr) -> String { + disassemble_with_kw(allocator, sexp, keyword_from_atom()) } pub fn assemble(allocator: &mut Allocator, s: &str) -> Result { diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index b1e3ef7e6..df5d74e6a 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -1493,7 +1493,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul )); } - let mut run_output = disassemble_with_kw(&mut allocator, result, keywords); + let mut run_output = disassemble_with_kw(&allocator, result, keywords); if let Some(ArgumentValue::ArgBool(true)) = parsed_args.get("dump") { let mut f = Stream::new(None); sexp_to_stream(&mut allocator, result, &mut f); @@ -1509,7 +1509,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul format!( "FAIL: {} {}", ex.1, - disassemble_with_kw(&mut allocator, ex.0, keywords) + disassemble_with_kw(&allocator, ex.0, keywords) ) })); @@ -1545,7 +1545,9 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul only_exn, &log_content, symbol_table, - &disassemble, + // Clippy: disassemble no longer requires mutability, + // but this callback interface delivers it. + &|a: &mut Allocator, sexp: NodePtr| disassemble(a, sexp), ); } else { stdout.write_str("\n"); @@ -1555,7 +1557,8 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul only_exn, &log_content, symbol_table, - &disassemble, + // Same as above. + &|a: &mut Allocator, sexp: NodePtr| disassemble(a, sexp), ); } } diff --git a/src/classic/clvm_tools/stages/stage_2/compile.rs b/src/classic/clvm_tools/stages/stage_2/compile.rs index bf433bdf1..2f221c8f4 100644 --- a/src/classic/clvm_tools/stages/stage_2/compile.rs +++ b/src/classic/clvm_tools/stages/stage_2/compile.rs @@ -321,7 +321,7 @@ pub fn try_expand_macro_for_atom( } fn get_macro_program( - allocator: &mut Allocator, + allocator: &Allocator, operator: &[u8], macro_lookup: NodePtr, ) -> Result, EvalErr> { @@ -448,7 +448,7 @@ enum SymbolResult { } fn find_symbol_match( - allocator: &mut Allocator, + allocator: &Allocator, opname: &[u8], r: NodePtr, symbol_table: NodePtr, diff --git a/src/classic/clvm_tools/stages/stage_2/inline.rs b/src/classic/clvm_tools/stages/stage_2/inline.rs index e47abbf73..d0db520f1 100644 --- a/src/classic/clvm_tools/stages/stage_2/inline.rs +++ b/src/classic/clvm_tools/stages/stage_2/inline.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; // (@ name substructure) // then return name and substructure. pub fn is_at_capture( - allocator: &mut Allocator, + allocator: &Allocator, tree_first: NodePtr, tree_rest: NodePtr, ) -> Option<(NodePtr, NodePtr)> { diff --git a/src/classic/clvm_tools/stages/stage_2/module.rs b/src/classic/clvm_tools/stages/stage_2/module.rs index 5bc0897bb..0c1d64952 100644 --- a/src/classic/clvm_tools/stages/stage_2/module.rs +++ b/src/classic/clvm_tools/stages/stage_2/module.rs @@ -130,7 +130,7 @@ fn build_used_constants_names( new_names = HashSet::new(); for name in iterate_names { - let functions_and_macros = vec![functions.get(&name), macro_as_dict.get(&name)]; + let functions_and_macros = [functions.get(&name), macro_as_dict.get(&name)]; let matching_names_1 = functions_and_macros .iter() diff --git a/src/classic/clvm_tools/stages/stage_2/operators.rs b/src/classic/clvm_tools/stages/stage_2/operators.rs index c9913dd62..326d00f39 100644 --- a/src/classic/clvm_tools/stages/stage_2/operators.rs +++ b/src/classic/clvm_tools/stages/stage_2/operators.rs @@ -209,7 +209,7 @@ impl CompilerOperatorsInternal { } } - fn write(&self, allocator: &mut Allocator, sexp: NodePtr) -> Response { + fn write(&self, allocator: &Allocator, sexp: NodePtr) -> Response { if let SExp::Pair(filename_sexp, r) = allocator.sexp(sexp) { if let SExp::Pair(data, _) = allocator.sexp(r) { if let SExp::Atom() = allocator.sexp(filename_sexp) { @@ -280,7 +280,7 @@ impl CompilerOperatorsInternal { pub fn set_symbol_table( &self, - allocator: &mut Allocator, + allocator: &Allocator, table: NodePtr, ) -> Result { if let Some(symtable) = diff --git a/src/classic/clvm_tools/stages/stage_2/optimize.rs b/src/classic/clvm_tools/stages/stage_2/optimize.rs index 5e1e2306d..199262a6d 100644 --- a/src/classic/clvm_tools/stages/stage_2/optimize.rs +++ b/src/classic/clvm_tools/stages/stage_2/optimize.rs @@ -136,7 +136,7 @@ pub fn constant_optimizer( Ok(r) } -pub fn is_args_call(allocator: &mut Allocator, r: NodePtr) -> bool { +pub fn is_args_call(allocator: &Allocator, r: NodePtr) -> bool { if let SExp::Atom() = allocator.sexp(r) { // Only r in scope. let buf = allocator.atom(r); diff --git a/src/compiler/dialect.rs b/src/compiler/dialect.rs index 19f5ad92a..953bc553d 100644 --- a/src/compiler/dialect.rs +++ b/src/compiler/dialect.rs @@ -85,10 +85,13 @@ lazy_static! { }; } -fn include_dialect(allocator: &mut Allocator, e: &[NodePtr]) -> Option { +fn include_dialect(allocator: &Allocator, e: &[NodePtr]) -> Option { let include_keyword_sexp = e[0]; let name_sexp = e[1]; - if let (SExp::Atom(), SExp::Atom()) = (allocator.sexp(include_keyword_sexp), allocator.sexp(name_sexp)) { + if let (SExp::Atom(), SExp::Atom()) = ( + allocator.sexp(include_keyword_sexp), + allocator.sexp(name_sexp), + ) { if allocator.atom(include_keyword_sexp) == "include".as_bytes().to_vec() { if let Some(dialect) = KNOWN_DIALECTS.get(&decode_string(allocator.atom(name_sexp))) { return Some(dialect.accepted.clone()); diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index a81245538..f4901dfd5 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -814,7 +814,8 @@ impl<'info> Evaluator { prog_args, )))) } else if call.name == "com".as_bytes() { - let use_body = self.make_com_module(&call.loc, prog_args, arguments_to_convert[0].to_sexp()); + let use_body = + self.make_com_module(&call.loc, prog_args, arguments_to_convert[0].to_sexp()); let compiled = self.compile_code(allocator, false, use_body)?; let compiled_borrowed: &SExp = compiled.borrow(); Ok(Rc::new(BodyForm::Quoted(compiled_borrowed.clone()))) diff --git a/src/compiler/inline.rs b/src/compiler/inline.rs index 0d27e8875..604014e2b 100644 --- a/src/compiler/inline.rs +++ b/src/compiler/inline.rs @@ -262,7 +262,7 @@ fn get_inline_callable( /// expressions given in the ultimate original call. This allows inline functions /// to seem to call each other as long as there's no cycle. fn make_args_for_call_from_inline( - visited_inlines: &mut HashSet>, + visited_inlines: &HashSet>, runner: Rc, opts: Rc, compiler: &PrimaryCodegen, diff --git a/src/compiler/repl.rs b/src/compiler/repl.rs index ce8101f2c..e8c228311 100644 --- a/src/compiler/repl.rs +++ b/src/compiler/repl.rs @@ -92,7 +92,7 @@ impl Repl { let loc = Srcloc::start(&opts.filename()); let mut toplevel_forms = HashSet::new(); - for w in vec!["defun", "defun-inline", "defconstant", "defmacro"].iter() { + for w in ["defun", "defun-inline", "defconstant", "defmacro"].iter() { toplevel_forms.insert(w.to_string()); } From 81ea5225ce313e522017f142bb6e71770d835b59 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 4 Aug 2023 11:04:30 -0700 Subject: [PATCH 084/196] Add comment --- src/compiler/clvm.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compiler/clvm.rs b/src/compiler/clvm.rs index 3d4eed54a..02e350711 100644 --- a/src/compiler/clvm.rs +++ b/src/compiler/clvm.rs @@ -192,6 +192,9 @@ fn eval_args( sexp = b.clone(); } _ => { + // This change was moved to: + // https://github.com/Chia-Network/clvm_tools_rs/pull/205 + // and will be removed when that's in. if !truthy(sexp.clone()) { return Ok(RunStep::Op(head, context_, sexp, Some(eval_list), parent)); } else { From cdf9d053747bfee7c9db664344b3fbc924644724 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 4 Aug 2023 20:34:03 -0700 Subject: [PATCH 085/196] Added more comments --- src/compiler/codegen.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 775fe04ce..d4c311322 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -182,8 +182,11 @@ fn create_name_lookup_( } } +// Tell whether there's a non-inline defun called 'name' in this program. +// If so, the reference to this name is a reference to a function, which +// will make variable references to it capture the program's function +// environment. fn is_defun_in_codegen(compiler: &PrimaryCodegen, name: &[u8]) -> bool { - // Check for an input defun that matches the name. for h in compiler.original_helpers.iter() { if matches!(h, HelperForm::Defun(false, _)) && h.name() == name { return true; @@ -193,6 +196,8 @@ fn is_defun_in_codegen(compiler: &PrimaryCodegen, name: &[u8]) -> bool { false } +// At the CLVM level, given a list of clvm expressios, make an expression +// that contains that list using conses. fn make_list(loc: Srcloc, elements: Vec>) -> Rc { let mut res = Rc::new(SExp::Nil(loc.clone())); for e in elements.iter().rev() { @@ -202,7 +207,12 @@ fn make_list(loc: Srcloc, elements: Vec>) -> Rc { } // -// Write an expression that conses the left env. +// Get the clvm expression that represents the indicated function as a +// callable value using the CLVM a operator. This value can be returned +// and even passed to another program because it carries the required +// environment to call functions it depends on from the call site. +// +// To do this, it writes an expression that conses the left env. // // (list (q . 2) (c (q . 1) n) (list (q . 4) (c (q . 1) 2) (q . 1))) // @@ -243,6 +253,11 @@ fn create_name_lookup( compiler: &PrimaryCodegen, l: Srcloc, name: &[u8], + // If the lookup is in head position, then it is a lookup as a callable, + // otherwise it's a lookup as a variable, which means that if a function + // is named, it will be built into an expression that allows it to be + // called by a CLVM 'a' operator as one would expect, regardless of how + // it integrates with the rest of the program it lives in. as_variable: bool, ) -> Result, CompileErr> { compiler @@ -256,6 +271,8 @@ fn create_name_lookup( // callable like a lambda by repeating the left env into it. let find_program = Rc::new(SExp::Integer(l.clone(), i.to_bigint().unwrap())); if as_variable && is_defun_in_codegen(compiler, name) { + // It's a defun. Harden the result so it is callable + // directly by the CLVM 'a' operator. lambda_for_defun(l.clone(), find_program) } else { find_program From cf243f62d81c666930fd9d31f5191e53dae37b47 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 08:57:40 -0700 Subject: [PATCH 086/196] lambda codegen doesn't (for now) need error so hosting doesn't either --- src/compiler/codegen.rs | 31 ++++++++++++++++++------------- src/compiler/compiler.rs | 2 +- src/compiler/lambda.rs | 5 +++-- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index f37221275..da4e50672 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -306,6 +306,8 @@ pub fn get_callable( SExp::Atom(l, name) => { let macro_def = compiler.macros.get(name); let inline = compiler.inlines.get(name); + // We're getting a callable, so the access requested is not as + // a variable. let defun = create_name_lookup(compiler, l.clone(), name, false); let prim = get_prim(l.clone(), compiler.prims.clone(), name); let atom_is_com = *name == "com".as_bytes().to_vec(); @@ -645,6 +647,9 @@ pub fn generate_expr_code( Rc::new(SExp::Integer(l.clone(), bi_one())), )) } else { + // This is as a variable access, given that we've got + // a Value bodyform containing an Atom, so if a defun + // is returned, it should be a packaged callable. create_name_lookup(compiler, l.clone(), atom, true) .map(|f| Ok(CompiledCode(l.clone(), f))) .unwrap_or_else(|_| { @@ -909,11 +914,11 @@ pub fn hoist_body_let_binding( outer_context: Option>, args: Rc, body: Rc, -) -> Result<(Vec, Rc), CompileErr> { +) -> (Vec, Rc) { match body.borrow() { BodyForm::Let(LetFormKind::Sequential, letdata) => { if letdata.bindings.is_empty() { - return Ok((vec![], letdata.body.clone())); + return (vec![], letdata.body.clone()); } // If we're here, we're in the middle of hoisting. @@ -956,7 +961,7 @@ pub fn hoist_body_let_binding( let mut revised_bindings = Vec::new(); for b in letdata.bindings.iter() { let (mut new_helpers, new_binding) = - hoist_body_let_binding(outer_context.clone(), args.clone(), b.body.clone())?; + hoist_body_let_binding(outer_context.clone(), args.clone(), b.body.clone()); out_defuns.append(&mut new_helpers); revised_bindings.push(Rc::new(Binding { loc: b.loc.clone(), @@ -1004,14 +1009,14 @@ pub fn hoist_body_let_binding( // Calling desugared let so we decide what the tail looks like. let final_call = BodyForm::Call(letdata.loc.clone(), call_args, None); - Ok((out_defuns, Rc::new(final_call))) + (out_defuns, Rc::new(final_call)) } BodyForm::Call(l, list, tail) => { let mut vres = Vec::new(); let mut new_call_list = vec![list[0].clone()]; for i in list.iter().skip(1) { let (mut new_helpers, new_arg) = - hoist_body_let_binding(outer_context.clone(), args.clone(), i.clone())?; + hoist_body_let_binding(outer_context.clone(), args.clone(), i.clone()); new_call_list.push(new_arg); vres.append(&mut new_helpers); } @@ -1019,17 +1024,17 @@ pub fn hoist_body_let_binding( // Ensure that we hoist a let occupying the &rest tail. let new_tail = if let Some(t) = tail.as_ref() { let (mut new_tail_helpers, new_tail) = - hoist_body_let_binding(outer_context, args, t.clone())?; + hoist_body_let_binding(outer_context, args, t.clone()); vres.append(&mut new_tail_helpers); Some(new_tail) } else { None }; - Ok(( + ( vres, Rc::new(BodyForm::Call(l.clone(), new_call_list, new_tail)), - )) + ) } BodyForm::Lambda(letdata) => { let new_function_args = Rc::new(SExp::Cons( @@ -1042,8 +1047,8 @@ pub fn hoist_body_let_binding( Some(new_function_args.clone()), new_function_args.clone(), letdata.body.clone(), - )?; - let new_expr = lambda_codegen(&new_function_name, letdata)?; + ); + let new_expr = lambda_codegen(&new_function_name, letdata); let function = HelperForm::Defun( false, DefunData { @@ -1057,9 +1062,9 @@ pub fn hoist_body_let_binding( }, ); new_helpers_from_body.push(function); - Ok((new_helpers_from_body, Rc::new(new_expr))) + (new_helpers_from_body, Rc::new(new_expr)) } - _ => Ok((Vec::new(), body.clone())), + _ => (Vec::new(), body.clone()), } } @@ -1076,7 +1081,7 @@ pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Result BodyForm { // (list 4 (list 4 (c 1 compose_captures) @)) // ) // -pub fn lambda_codegen(name: &[u8], ldata: &LambdaData) -> Result { +pub fn lambda_codegen(name: &[u8], ldata: &LambdaData) -> BodyForm { // Code to retrieve and quote the captures. let quote_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![1])); let apply_atom = BodyForm::Value(SExp::Atom(ldata.loc.clone(), vec![2])); @@ -126,7 +126,8 @@ pub fn lambda_codegen(name: &[u8], ldata: &LambdaData) -> Result Date: Mon, 7 Aug 2023 09:01:54 -0700 Subject: [PATCH 087/196] Reverse a change that mattered when lambdas were implemend as a kind of mod. This change should probably resurface elsewhere as it's more correct, but may not be breaking anything right now. --- src/compiler/codegen.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index da4e50672..31c8edb31 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -710,8 +710,7 @@ pub fn generate_expr_code( } BodyForm::Mod(_, program) => { // A mod form yields the compiled code. - let without_env = opts.set_start_env(None).set_in_defun(false); - let code = codegen(allocator, runner, without_env, program, &mut HashMap::new())?; + let code = codegen(allocator, runner, opts, program, &mut HashMap::new())?; Ok(CompiledCode( program.loc.clone(), Rc::new(SExp::Cons( From 78477a89c1e7ab8efd5dd51d6bbdbcb3cbb7c0d4 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 09:18:48 -0700 Subject: [PATCH 088/196] Add more comments --- src/compiler/codegen.rs | 29 ++++++++++++++++++++--------- src/compiler/compiler.rs | 2 +- src/compiler/evaluate.rs | 4 ++-- src/compiler/lambda.rs | 7 +++---- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 31c8edb31..f271fe6d4 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -1021,14 +1021,12 @@ pub fn hoist_body_let_binding( } // Ensure that we hoist a let occupying the &rest tail. - let new_tail = if let Some(t) = tail.as_ref() { + let new_tail = tail.as_ref().map(|t| { let (mut new_tail_helpers, new_tail) = hoist_body_let_binding(outer_context, args, t.clone()); vres.append(&mut new_tail_helpers); - Some(new_tail) - } else { - None - }; + new_tail + }); ( vres, @@ -1036,6 +1034,15 @@ pub fn hoist_body_let_binding( ) } BodyForm::Lambda(letdata) => { + // A lambda is exactly the same as + // 1) A function whose argument list is the captures plus the + // non-capture arguments. + // 2) A call site which includes a reference to the function + // surrounded with a structure that curries on the capture + // arguments. + + // Compose the function and return it as a desugared function. + // The functions desugared here also come from let bindings. let new_function_args = Rc::new(SExp::Cons( letdata.loc.clone(), letdata.capture_args.clone(), @@ -1047,12 +1054,11 @@ pub fn hoist_body_let_binding( new_function_args.clone(), letdata.body.clone(), ); - let new_expr = lambda_codegen(&new_function_name, letdata); let function = HelperForm::Defun( false, DefunData { loc: letdata.loc.clone(), - name: new_function_name, + name: new_function_name.clone(), kw: letdata.kw.clone(), nl: letdata.args.loc(), orig_args: new_function_args.clone(), @@ -1061,13 +1067,18 @@ pub fn hoist_body_let_binding( }, ); new_helpers_from_body.push(function); + + // new_expr is the generated code at the call site. The reference + // to the actual function additionally is enriched by a left-env + // reference that gives it access to the program. + let new_expr = lambda_codegen(&new_function_name, letdata); (new_helpers_from_body, Rc::new(new_expr)) } _ => (Vec::new(), body.clone()), } } -pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Result, CompileErr> { +pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Vec { let mut result = helpers.to_owned(); let mut i = 0; @@ -1109,7 +1120,7 @@ pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Result bool { ) } -pub fn make_operator1(l: &Srcloc, op: String, arg: Rc) -> BodyForm { +fn make_operator1(l: &Srcloc, op: String, arg: Rc) -> BodyForm { BodyForm::Call( l.clone(), vec![ @@ -145,7 +145,7 @@ pub fn make_operator1(l: &Srcloc, op: String, arg: Rc) -> BodyForm { ) } -pub fn make_operator2(l: &Srcloc, op: String, arg1: Rc, arg2: Rc) -> BodyForm { +fn make_operator2(l: &Srcloc, op: String, arg1: Rc, arg2: Rc) -> BodyForm { BodyForm::Call( l.clone(), vec![ diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 13c451715..36082d860 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -3,16 +3,15 @@ use std::rc::Rc; use crate::compiler::clvm::truthy; use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts, LambdaData}; -use crate::compiler::evaluate::make_operator2; use crate::compiler::frontend::compile_bodyform; use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; fn make_captures(opts: Rc, sexp: Rc) -> Result, CompileErr> { if let SExp::Cons(l, f, r) = sexp.borrow() { - Ok(Rc::new(make_operator2( - l, - "c".to_string(), + Ok(Rc::new(make_operator( + l.clone(), + 4, make_captures(opts.clone(), f.clone())?, make_captures(opts, r.clone())?, ))) From d7a62d979b77a0fe46338477fa0525a62de93d5e Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 09:22:52 -0700 Subject: [PATCH 089/196] Reverse a change which i think cleans things up but is not essential --- src/compiler/rename.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index c58fdb7a5..ae543bd26 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -173,6 +173,7 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B } BodyForm::Mod(l, prog) => BodyForm::Mod(l.clone(), prog.clone()), + // Rename lambda arguments down the lexical scope. BodyForm::Lambda(ldata) => { let renamed_capture_inputs = Rc::new(rename_in_bodyform(namemap, ldata.captures.clone())); @@ -353,7 +354,6 @@ fn rename_args_helperform(h: &HelperForm) -> HelperForm { } let local_renamed_arg = rename_in_cons(&local_namemap, defun.args.clone()); let local_renamed_body = rename_args_bodyform(defun.body.borrow()); - let renamed_bodyform = rename_in_bodyform(&local_namemap, Rc::new(local_renamed_body)); HelperForm::Defun( *inline, DefunData { @@ -363,7 +363,10 @@ fn rename_args_helperform(h: &HelperForm) -> HelperForm { name: defun.name.clone(), orig_args: defun.orig_args.clone(), args: local_renamed_arg, - body: Rc::new(renamed_bodyform), + body: Rc::new(rename_in_bodyform( + &local_namemap, + Rc::new(local_renamed_body), + )), }, ) } From d521ecfa85e79aafa7d6f5e89d9c0f92f07d347d Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 09:37:52 -0700 Subject: [PATCH 090/196] Add a tail lambda to ensure it gets desugared right --- src/tests/compiler/compiler.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index f36cd5dd0..be932b405 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1634,3 +1634,18 @@ fn test_simple_rest_call_inline() { let res = run_string(&prog, &"(13 99 144)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "768"); } + +#[test] +fn test_simple_rest_lambda() { + let prog = indoc! {" +(mod (Z X) + (include *standard-cl-21*) + + (defun silly-lambda-consumer (Q F) (a F (list Q))) + + (silly-lambda-consumer &rest (list X (lambda ((& Z) X) (* Z X)))) + )"} + .to_string(); + let res = run_string(&prog, &"(13 51)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "663"); +} From 32deee52a3b2b226708391f500d88bbb632ee3e1 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 09:41:34 -0700 Subject: [PATCH 091/196] Add a lambda from lambda test --- src/tests/compiler/compiler.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index be932b405..3d2a26f1d 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1649,3 +1649,18 @@ fn test_simple_rest_lambda() { let res = run_string(&prog, &"(13 51)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "663"); } + +#[test] +fn test_lambda_in_lambda() { + let prog = indoc! {" +(mod (Z X) + (include *standard-cl-21*) + + (defun silly-lambda-consumer (Q F) (a F (list Q))) + + (a (silly-lambda-consumer X (lambda ((& Z) X) (lambda ((& Z X)) (* Z X)))) ()) + )"} + .to_string(); + let res = run_string(&prog, &"(13 51)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "663"); +} From 8aade0eb3f44c14f43faa90c1ffe147dcc35b70b Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 10:53:52 -0700 Subject: [PATCH 092/196] fmt + clippy --- src/compiler/lambda.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 36082d860..1ce93538f 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -110,7 +110,7 @@ pub fn lambda_codegen(name: &[u8], ldata: &LambdaData) -> BodyForm { ldata.captures.clone(), ); - let lambda_output = make_list( + make_list( ldata.loc.clone(), &[ apply_atom, @@ -124,9 +124,7 @@ pub fn lambda_codegen(name: &[u8], ldata: &LambdaData) -> BodyForm { ), make_list(ldata.loc.clone(), &[cons_atom, compose_captures, whole_env]), ], - ); - - lambda_output + ) } pub fn handle_lambda( From 98a9601ce6726c2d6d1e673d17663a4495918539 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 11:25:11 -0700 Subject: [PATCH 093/196] Ensure that rest args are destructured so that we can separate arguments. This mirrors other forms of chialisp runtime where a tail argument is necessarily evaluated eariler than positional arguments for destructuring purposes --- src/compiler/evaluate.rs | 31 +++++++++++++++++++++++++++++-- src/tests/compiler/repl.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index eeb05cf1d..7f8249e7c 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -273,6 +273,19 @@ fn arg_inputs_primitive(arginputs: Rc) -> bool { } } +fn decons_args( + l: &Srcloc, + formed_tail: Rc, +) -> ArgInputs { + if let Some((head, tail)) = match_cons(formed_tail.clone()) { + let arg_head = decons_args(l, head.clone()); + let arg_tail = decons_args(l, tail.clone()); + ArgInputs::Pair(Rc::new(arg_head), Rc::new(arg_tail)) + } else { + ArgInputs::Whole(formed_tail) + } +} + fn build_argument_captures( l: &Srcloc, arguments_to_convert: &[Rc], @@ -280,7 +293,7 @@ fn build_argument_captures( args: Rc, ) -> Result, Rc>, CompileErr> { let formed_tail = tail.unwrap_or_else(|| Rc::new(BodyForm::Quoted(SExp::Nil(l.clone())))); - let mut formed_arguments = ArgInputs::Whole(formed_tail); + let mut formed_arguments = decons_args(l, formed_tail); for i_reverse in 0..arguments_to_convert.len() { let i = arguments_to_convert.len() - i_reverse - 1; @@ -1041,10 +1054,24 @@ impl<'info> Evaluator { return Ok(call.original.clone()); } + let translated_tail = + if let Some(t) = call.tail.as_ref() { + Some(self.shrink_bodyform_visited( + allocator, + visited, + prog_args.clone(), + env, + t.clone(), + only_inline + )?) + } else { + None + }; + let argument_captures_untranslated = build_argument_captures( &call.loc.clone(), arguments_to_convert, - call.tail.clone(), + translated_tail.clone(), defun.args.clone(), )?; diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index b2a14d953..adeaa0b7d 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -404,3 +404,35 @@ fn test_eval_new_bls_operator() { "(q)" ); } + +#[test] +fn test_repl_base_lambda_case() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun F (X F) (a F (list X)))".to_string(), + "(F 3 (lambda (Y) (+ Y 9)))".to_string(), + ], + None + ) + .unwrap() + .unwrap(), + "(q . 12)" + ); +} + +#[test] +fn test_repl_rest_lambda_case() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun F (X F) (a F (list X)))".to_string(), + "(F &rest (list 3 (lambda (Y) (+ Y 9))))".to_string() + ], + None + ) + .unwrap() + .unwrap(), + "(q . 12)" + ); +} From 3c10a5042bc5f6ee3fdddf99b802bfc9c8fa9d2b Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 11:25:37 -0700 Subject: [PATCH 094/196] fmt --- src/compiler/evaluate.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 7f8249e7c..58b3d8048 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -273,10 +273,7 @@ fn arg_inputs_primitive(arginputs: Rc) -> bool { } } -fn decons_args( - l: &Srcloc, - formed_tail: Rc, -) -> ArgInputs { +fn decons_args(l: &Srcloc, formed_tail: Rc) -> ArgInputs { if let Some((head, tail)) = match_cons(formed_tail.clone()) { let arg_head = decons_args(l, head.clone()); let arg_tail = decons_args(l, tail.clone()); @@ -1054,19 +1051,18 @@ impl<'info> Evaluator { return Ok(call.original.clone()); } - let translated_tail = - if let Some(t) = call.tail.as_ref() { - Some(self.shrink_bodyform_visited( - allocator, - visited, - prog_args.clone(), - env, - t.clone(), - only_inline - )?) - } else { - None - }; + let translated_tail = if let Some(t) = call.tail.as_ref() { + Some(self.shrink_bodyform_visited( + allocator, + visited, + prog_args.clone(), + env, + t.clone(), + only_inline, + )?) + } else { + None + }; let argument_captures_untranslated = build_argument_captures( &call.loc.clone(), From 30671ff8bc05b7979f216f350875be04523049e1 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 11:28:21 -0700 Subject: [PATCH 095/196] Ensure tricky applications of let forms in rest arguments work --- src/tests/compiler/compiler.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 3d2a26f1d..443b1cf11 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1664,3 +1664,33 @@ fn test_lambda_in_lambda() { let res = run_string(&prog, &"(13 51)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "663"); } + +#[test] +fn test_let_in_rest_0() { + let prog = indoc! {" +(mod (Z X) + (include *standard-cl-21*) + + (defun F (X) (+ X 3)) + + (F &rest (list (let ((Q (* X Z))) (+ Q 99)))) + )"} + .to_string(); + let res = run_string(&prog, &"(3 2)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "108"); +} + +#[test] +fn test_let_in_rest_1() { + let prog = indoc! {" +(mod (Z X) + (include *standard-cl-21*) + + (defun F (X) (+ X 3)) + + (F &rest (let ((Q (* X Z))) (list (+ Q 99)))) + )"} + .to_string(); + let res = run_string(&prog, &"(3 2)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "108"); +} From 2b38ad8663768a0bbe328436aac14d042a798b8a Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 11:31:46 -0700 Subject: [PATCH 096/196] clippy --- src/compiler/evaluate.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 58b3d8048..49583411a 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -273,10 +273,10 @@ fn arg_inputs_primitive(arginputs: Rc) -> bool { } } -fn decons_args(l: &Srcloc, formed_tail: Rc) -> ArgInputs { +fn decons_args(formed_tail: Rc) -> ArgInputs { if let Some((head, tail)) = match_cons(formed_tail.clone()) { - let arg_head = decons_args(l, head.clone()); - let arg_tail = decons_args(l, tail.clone()); + let arg_head = decons_args(head.clone()); + let arg_tail = decons_args(tail.clone()); ArgInputs::Pair(Rc::new(arg_head), Rc::new(arg_tail)) } else { ArgInputs::Whole(formed_tail) @@ -290,7 +290,7 @@ fn build_argument_captures( args: Rc, ) -> Result, Rc>, CompileErr> { let formed_tail = tail.unwrap_or_else(|| Rc::new(BodyForm::Quoted(SExp::Nil(l.clone())))); - let mut formed_arguments = decons_args(l, formed_tail); + let mut formed_arguments = decons_args(formed_tail); for i_reverse in 0..arguments_to_convert.len() { let i = arguments_to_convert.len() - i_reverse - 1; From 02107833afedcc42d13b3ca1f90353d3b470f3cf Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 11:35:30 -0700 Subject: [PATCH 097/196] Add new repl test --- src/tests/compiler/repl.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index adeaa0b7d..adefda905 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -436,3 +436,20 @@ fn test_repl_rest_lambda_case() { "(q . 12)" ); } + +#[test] +fn test_repl_lambda_with_captures_rest() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun map (F L) (if L (c (a F (list (f L))) (map F (r L))) ()))".to_string(), + "(defun F (X L) (map &rest (list (lambda ((& X) Y) (+ X Y)) L)))".to_string(), + "(F 3 (list 99 101 103))".to_string() + ], + None + ) + .unwrap() + .unwrap(), + "(q 102 104 106)" + ); +} From df41c1be2019093a32f61ef37e6939d27e7d2b7a Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 11:46:59 -0700 Subject: [PATCH 098/196] transport comment from base --- src/compiler/dialect.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compiler/dialect.rs b/src/compiler/dialect.rs index 953bc553d..ba2641489 100644 --- a/src/compiler/dialect.rs +++ b/src/compiler/dialect.rs @@ -102,6 +102,13 @@ fn include_dialect(allocator: &Allocator, e: &[NodePtr]) -> Option AcceptedDialect { let mut result = Default::default(); From 6fb7cd3fa91c98748438756a0a63d145cf4ab709 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 14:53:22 -0700 Subject: [PATCH 099/196] Add another higher order function test --- src/tests/compiler/repl.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tests/compiler/repl.rs b/src/tests/compiler/repl.rs index adefda905..d5c0977ca 100644 --- a/src/tests/compiler/repl.rs +++ b/src/tests/compiler/repl.rs @@ -453,3 +453,19 @@ fn test_repl_lambda_with_captures_rest() { "(q 102 104 106)" ); } + +#[test] +fn test_repl_lambda_with_captures_out_of_own_function() { + assert_eq!( + test_repl_outcome_with_stack_limit( + vec![ + "(defun F (X) (lambda ((& X) Y) (+ X Y)))".to_string(), + "(a (F 3) (list 4))".to_string(), + ], + None + ) + .unwrap() + .unwrap(), + "(q . 7)" + ); +} From 351c4f81ba7f9f636e22a95507f15c4530f12891 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 7 Aug 2023 18:04:37 -0700 Subject: [PATCH 100/196] Add a comment --- src/classic/clvm_tools/cmds.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 2039ff116..fbfd5fc4c 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -808,6 +808,14 @@ fn fix_log( } } +// A function which performs preprocessing on a whole program and renders the +// output to the user. +// +// This is used in the same way as cc -E in a C compiler; to see what +// preprocessing did to the source so you can debug and improve your macros. +// +// Without this, it's difficult for some to visualize how macro are functioning +// and what forms they output. fn perform_preprocessing( stdout: &mut Stream, opts: Rc, @@ -815,7 +823,19 @@ fn perform_preprocessing( program_text: &str, ) -> Result<(), CompileErr> { let srcloc = Srcloc::start(input_file); + // Parse the source file. let parsed = parse_sexp(srcloc.clone(), program_text.bytes())?; + // Get the detected dialect and compose a sigil that matches. + // Classic preprocessing (also shared by standard sigil 21 and 21) does macro + // expansion during the compile process, making all macros available to all + // code regardless of its lexical order and therefore isn't rendered in a + // unified way (for example, 'com' and 'mod' forms invoke macros when + // encountered and expanded. By contrast strict mode reads the macros and + // evaluates them in that order (as in C). + // + // The result is fully rendered before the next stage of compilation so that + // it can be inspected and so that the execution environment for macros is + // fully and cleanly separated from compile time. let stepping_form_text = match opts.dialect().stepping { Some(21) => Some("(include *strict-cl-21*)".to_string()), Some(n) => Some(format!("(include *standard-cl-{n}*)")), From 6725447787faa945f3ac0f400b1f7dc0ab0ffcd9 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 8 Aug 2023 08:49:28 -0700 Subject: [PATCH 101/196] Add more commentary --- src/compiler/codegen.rs | 14 ++++++++++++++ src/compiler/rename.rs | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index e9666abde..1dc4ecf09 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -563,6 +563,16 @@ pub fn generate_expr_code( create_name_lookup(compiler, l.clone(), atom) .map(|f| Ok(CompiledCode(l.clone(), f))) .unwrap_or_else(|_| { + // Finally enable strictness for variable names. + // This is possible because the modern macro system + // takes great care to preserve as much information + // from the source code as possible. + // + // When we come here in strict mode, we have + // a string, integer or atom depending on the + // user's desire and the explicitly generated + // result from the macro, therefore we can return + // an error if this atom didn't have a binding. if opts.dialect().strict { return Err(CompileErr( l.clone(), @@ -587,6 +597,10 @@ pub fn generate_expr_code( } } SExp::Integer(l, i) => { + // This code can assume that an integer is an integer because + // strict mode closes the necessary loophole below. Values + // intended as variable names are never crushed into integer + // like values from modern macros. if opts.dialect().strict { return generate_expr_code( allocator, diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 319b0e819..c8219175a 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -183,6 +183,8 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B } } +/// Given a set of sequential bindings, create a stack of let forms that have +/// the same meaning. This is used to propogate renaming. pub fn desugar_sequential_let_bindings( bindings: &[Rc], body: &BodyForm, @@ -373,6 +375,8 @@ fn rename_in_compileform(namemap: &HashMap, Vec>, c: Rc } } +/// For all the HelperForms in a CompileForm, do renaming in them so that all +/// unique variable bindings in the program have unique names. pub fn rename_children_compileform(c: &CompileForm) -> CompileForm { let local_renamed_helpers = c.helpers.iter().map(rename_args_helperform).collect(); let local_renamed_body = rename_args_bodyform(c.exp.borrow()); @@ -385,6 +389,12 @@ pub fn rename_children_compileform(c: &CompileForm) -> CompileForm { } } +/// Given a compileform, perform renaming in descendants so that every variable +/// name that lives in a different scope has a unique name. This allows +/// compilation to treat identical forms as equivalent and ensures that forms +/// that look the same but refer to different variables are different. It also +/// ensures that future tricky variable name uses decide on one binding from their +/// lexical scope. pub fn rename_args_compileform(c: &CompileForm) -> CompileForm { let new_names = invent_new_names_sexp(c.args.clone()); let mut local_namemap = HashMap::new(); From f183d5b78a367c020ae68763cb97ecb7206c6713 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 9 Aug 2023 15:07:12 -0700 Subject: [PATCH 102/196] Compiled macros rather than interpreted in the evaluator --- src/compiler/compiler.rs | 26 +- src/compiler/evaluate.rs | 59 +--- src/compiler/frontend.rs | 8 +- src/compiler/preprocessor/macros.rs | 530 ++++++---------------------- src/compiler/preprocessor/mod.rs | 68 ++-- src/compiler/runtypes.rs | 10 + src/compiler/sexp.rs | 2 +- src/tests/compiler/preprocessor.rs | 2 +- 8 files changed, 201 insertions(+), 504 deletions(-) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index fc196fae5..00c06c47c 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -158,16 +158,13 @@ fn fe_opt( }) } -pub fn compile_pre_forms( +pub fn compile_from_compileform( allocator: &mut Allocator, runner: Rc, opts: Rc, - pre_forms: &[Rc], + p0: CompileForm, symbol_table: &mut HashMap, ) -> Result { - // Resolve includes, convert program source to lexemes - let p0 = frontend(opts.clone(), pre_forms)?; - let p1 = if opts.frontend_opt() { // Front end optimization fe_opt(allocator, runner.clone(), opts.clone(), p0)? @@ -197,6 +194,25 @@ pub fn compile_pre_forms( codegen(allocator, runner, opts, &p2, symbol_table) } +pub fn compile_pre_forms( + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + pre_forms: &[Rc], + symbol_table: &mut HashMap, +) -> Result { + // Resolve includes, convert program source to lexemes + let p0 = frontend(opts.clone(), pre_forms)?; + + compile_from_compileform( + allocator, + runner, + opts, + p0, + symbol_table + ) +} + pub fn compile_file( allocator: &mut Allocator, runner: Rc, diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index f4901dfd5..e0b4f7da6 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -9,7 +9,7 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::{run, PrimOverride}; +use crate::compiler::clvm::run; use crate::compiler::codegen::codegen; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ @@ -135,61 +135,6 @@ pub struct Evaluator { ignore_exn: bool, } -fn compile_to_run_err(e: CompileErr) -> RunFailure { - match e { - CompileErr(l, e) => RunFailure::RunErr(l, e), - } -} - -impl PrimOverride for Evaluator { - fn try_handle( - &self, - head: Rc, - _context: Rc, - tail: Rc, - ) -> Result>, RunFailure> { - let have_args: Vec> = if let Some(args_list) = tail.proper_list() { - args_list - .iter() - .map(|e| Rc::new(BodyForm::Quoted(e.clone()))) - .collect() - } else { - return Ok(None); - }; - - if let SExp::Atom(hl, head_atom) = head.borrow() { - let mut call_args = vec![Rc::new(BodyForm::Value(SExp::Atom( - hl.clone(), - head_atom.clone(), - )))]; - call_args.append(&mut have_args.clone()); - // Primitives can't have tails. - let call_form = Rc::new(BodyForm::Call(head.loc(), call_args, None)); - - for x in self.extensions.iter() { - if let Some(res) = x - .try_eval( - self, - Rc::new(SExp::Nil(head.loc())), - &HashMap::new(), - &head.loc(), - head_atom, - &have_args, - call_form.clone(), - ) - .map_err(compile_to_run_err)? - { - return dequote(head.loc(), res) - .map_err(compile_to_run_err) - .map(Some); - } - } - } - - Ok(None) - } -} - fn select_helper(bindings: &[HelperForm], name: &[u8]) -> Option { for b in bindings.iter() { if b.name() == name { @@ -1383,7 +1328,7 @@ impl<'info> Evaluator { self.prims.clone(), prim, args, - Some(self), + None, Some(PRIM_RUN_LIMIT), ) .map_err(|e| match e { diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 7e2b38348..d936a8d75 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -251,8 +251,9 @@ fn make_let_bindings( ) -> Result>, CompileErr> { let err = Err(CompileErr( body.loc(), - "Bad binding tail ".to_string() + &body.to_string(), + format!("Bad binding tail {body:?}") )); + eprintln!("make_let_bindings {body}"); match body.borrow() { SExp::Nil(_) => Ok(vec![]), SExp::Cons(_, head, tl) => head @@ -271,7 +272,10 @@ fn make_let_bindings( result.append(&mut rest_bindings); Ok(result) } - _ => err.clone(), + _ => { + eprintln!("crap {body:?}"); + err.clone() + } }) .unwrap_or_else(|| err.clone()), _ => err, diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 9eae22249..859d8c79b 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -2,31 +2,24 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::rc::Rc; -use clvmr::allocator::Allocator; use num_bigint::ToBigInt; use num_traits::ToPrimitive; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; -use crate::compiler::clvm::truthy; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompilerOpts}; -use crate::compiler::evaluate::{EvalExtension, Evaluator}; -use crate::compiler::preprocessor::dequote; -use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::clvm::PrimOverride; +use crate::compiler::comptypes::{CompileErr, CompilerOpts}; +use crate::compiler::runtypes::RunFailure; +use crate::compiler::sexp::{decode_string, printable, SExp}; use crate::compiler::srcloc::Srcloc; use crate::util::{number_from_u8, Number}; // If the bodyform represents a constant, only match a quoted string. -fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { +fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { let is_string = match body.borrow() { - BodyForm::Quoted(SExp::QuotedString(_, b'x', _)) => None, - BodyForm::Quoted(SExp::QuotedString(al, _, an)) => Some((al.clone(), an.clone())), - BodyForm::Value(SExp::QuotedString(_, b'x', _)) => None, - BodyForm::Value(SExp::QuotedString(al, _, an)) => Some((al.clone(), an.clone())), - BodyForm::Quoted(_) => None, - _ => { - return Ok(None); - } + SExp::QuotedString(_, b'x', _) => None, + SExp::QuotedString(al, _, an) => Some((al.clone(), an.clone())), + _ => None }; if let Some((loc, s)) = is_string { @@ -36,13 +29,11 @@ fn match_quoted_string(body: Rc) -> Result)>, } } -fn match_atom(body: Rc) -> Result)>, CompileErr> { - if let BodyForm::Quoted(SExp::Atom(al, an)) = body.borrow() { +fn match_atom(body: Rc) -> Result)>, CompileErr> { + if let SExp::Atom(al, an) = body.borrow() { Ok(Some((al.clone(), an.clone()))) - } else if let BodyForm::Quoted(_) = body.borrow() { - Err(CompileErr(body.loc(), "atom required".to_string())) } else { - Ok(None) + Err(CompileErr(body.loc(), "atom required".to_string())) } } @@ -51,23 +42,31 @@ enum MatchedNumber { MatchedHex(Srcloc, Vec), } -fn match_number(body: Rc) -> Result, CompileErr> { +fn match_number(body: Rc) -> Result, CompileErr> { match body.borrow() { - BodyForm::Quoted(SExp::Integer(il, n)) => { - Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))) + SExp::Integer(il, n) => { + return Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))); } - BodyForm::Quoted(SExp::QuotedString(ql, b'x', b)) => { - Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))) + SExp::QuotedString(ql, b'x', b) => { + return Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))); } - BodyForm::Quoted(SExp::Nil(il)) => { - Ok(Some(MatchedNumber::MatchedInt(il.clone(), bi_zero()))) + SExp::Atom(al, b) => { + // An atom with unprintable characters is rendered as an integer. + if !printable(&b) { + let to_integer = number_from_u8(&b); + return Ok(Some(MatchedNumber::MatchedInt(al.clone(), to_integer))); + } } - BodyForm::Quoted(_) => Err(CompileErr(body.loc(), "number required".to_string())), - _ => Ok(None), + SExp::Nil(il) => { + return Ok(Some(MatchedNumber::MatchedInt(il.clone(), bi_zero()))); + } + _ => { } } + + Err(CompileErr(body.loc(), "number required".to_string())) } -fn numeric_value(body: Rc) -> Result { +fn numeric_value(body: Rc) -> Result { match match_number(body.clone())? { Some(MatchedNumber::MatchedInt(_, n)) => Ok(n), Some(MatchedNumber::MatchedHex(_, h)) => Ok(number_from_u8(&h)), @@ -75,7 +74,7 @@ fn numeric_value(body: Rc) -> Result { } } -fn usize_value(body: Rc) -> Result { +fn usize_value(body: Rc) -> Result { let n = numeric_value(body.clone())?; if let Some(res) = n.to_usize() { Ok(res) @@ -84,28 +83,6 @@ fn usize_value(body: Rc) -> Result { } } -fn reify_args( - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - args: &[Rc], -) -> Result>, CompileErr> { - let mut allocator = Allocator::new(); - let mut converted_args = Vec::new(); - for a in args.iter() { - let shrunk = evaluator.shrink_bodyform( - &mut allocator, - prog_args.clone(), - env, - a.clone(), - false, - None, - )?; - converted_args.push(shrunk); - } - Ok(converted_args) -} - /// A container for a function to evaluate in advanced preprocessor macros. /// We use this trait (which is very similar to the extension trait in Evaluator) /// as a definite handler for a specific named form, so optional returns aren't @@ -119,14 +96,9 @@ pub trait ExtensionFunction { #[allow(clippy::too_many_arguments)] fn try_eval( &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, loc: &Srcloc, - name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr>; + args: &[Rc], + ) -> Result, CompileErr>; } struct StringQ {} @@ -144,23 +116,15 @@ impl ExtensionFunction for StringQ { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let res = match match_quoted_string(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), - Ok(None) => { - return Ok(body); - } - Err(_) => SExp::Nil(loc.clone()), + _ => SExp::Nil(loc.clone()), }; - Ok(Rc::new(BodyForm::Quoted(res))) + Ok(Rc::new(res)) } } @@ -179,23 +143,15 @@ impl ExtensionFunction for NumberQ { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let res = match match_number(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), - Ok(None) => { - return Ok(body); - } - Err(_) => SExp::Nil(loc.clone()), + _ => SExp::Nil(loc.clone()), }; - Ok(Rc::new(BodyForm::Quoted(res))) + Ok(Rc::new(res)) } } @@ -214,23 +170,15 @@ impl ExtensionFunction for SymbolQ { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let res = match match_atom(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), - Ok(None) => { - return Ok(body); - } - Err(_) => SExp::Nil(loc.clone()), + _ => SExp::Nil(loc.clone()), }; - Ok(Rc::new(BodyForm::Quoted(res))) + Ok(Rc::new(res)) } } @@ -249,20 +197,15 @@ impl ExtensionFunction for SymbolToString { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { if let Some((loc, value)) = match_atom(args[0].clone())? { - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + Ok(Rc::new(SExp::QuotedString( loc, b'\"', value, - )))) + ))) } else { - Ok(body) + Err(CompileErr(args[0].loc(), "Not a symbol".to_string())) } } } @@ -282,18 +225,13 @@ impl ExtensionFunction for StringToSymbol { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - Ok(Rc::new(BodyForm::Quoted(SExp::Atom(loc, value)))) + Ok(Rc::new(SExp::Atom(loc, value))) } else { - Ok(body) + Err(CompileErr(args[0].loc(), "Not a string".to_string())) } } } @@ -313,14 +251,9 @@ impl ExtensionFunction for StringAppend { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, - _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + loc: &Srcloc, + args: &[Rc], + ) -> Result, CompileErr> { let mut out_vec = Vec::new(); let mut out_loc = None; for a in args.iter() { @@ -330,14 +263,14 @@ impl ExtensionFunction for StringAppend { } out_vec.append(&mut value); } else { - return Ok(body); + return Err(CompileErr(a.loc(), "not a quoted string".to_string())); } } - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( - out_loc.unwrap_or_else(|| body.loc()), + Ok(Rc::new(SExp::QuotedString( + out_loc.unwrap_or_else(|| loc.clone()), b'\"', out_vec, - )))) + ))) } } @@ -356,27 +289,22 @@ impl ExtensionFunction for NumberToString { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let match_res = match_number(args[0].clone())?; let (use_loc, int_val) = match &match_res { Some(MatchedNumber::MatchedInt(l, i)) => (l.clone(), i.clone()), Some(MatchedNumber::MatchedHex(l, h)) => (l.clone(), number_from_u8(h)), _ => { - return Ok(body); + return Err(CompileErr(args[0].loc(), "Not a number".to_string())); } }; - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + Ok(Rc::new(SExp::QuotedString( use_loc, b'\"', int_val.to_string().as_bytes().to_vec(), - )))) + ))) } } @@ -395,17 +323,12 @@ impl ExtensionFunction for StringToNumber { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, loc: &Srcloc, - _name: &[u8], - args: &[Rc], - _body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Ok(cvt_bi) = decode_string(&value).parse::() { - Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc, cvt_bi)))) + Ok(Rc::new(SExp::Integer(loc, cvt_bi))) } else { Err(CompileErr(loc, "bad number".to_string())) } @@ -433,23 +356,16 @@ impl ExtensionFunction for StringLength { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Some(len_bi) = value.len().to_bigint() { - Ok(Rc::new(BodyForm::Quoted(SExp::Integer(loc, len_bi)))) - } else { - Err(CompileErr(loc, "Error getting string length".to_string())) + return Ok(Rc::new(SExp::Integer(loc, len_bi))); } - } else { - Ok(body) } + + Err(CompileErr(args[0].loc(), "Error getting string length".to_string())) } } @@ -468,19 +384,14 @@ impl ExtensionFunction for Substring { fn try_eval( &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { + args: &[Rc], + ) -> Result, CompileErr> { let start_element = usize_value(args[1].clone())?; let end_element = usize_value(args[2].clone())?; match args[0].borrow() { - BodyForm::Quoted(SExp::QuotedString(l, ch, s)) => { + SExp::QuotedString(l, ch, s) => { if start_element > end_element || start_element > s.len() || end_element > s.len() { return Err(CompileErr( l.clone(), @@ -493,221 +404,13 @@ impl ExtensionFunction for Substring { .skip(start_element) .copied() .collect(); - Ok(Rc::new(BodyForm::Quoted(SExp::QuotedString( + Ok(Rc::new(SExp::QuotedString( l.clone(), *ch, result_value, - )))) - } - BodyForm::Quoted(_) => Err(CompileErr(body.loc(), "Not a string".to_string())), - _ => Ok(body), - } - } -} - -struct List {} - -impl List { - fn create() -> Rc { - Rc::new(List {}) - } -} - -impl ExtensionFunction for List { - fn required_args(&self) -> Option { - None - } - - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - _name: &[u8], - args: &[Rc], - _body: Rc, - ) -> Result, CompileErr> { - let mut allocator = Allocator::new(); - let mut res = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); - for a in args.iter().rev() { - res = Rc::new(BodyForm::Call( - loc.clone(), - vec![ - Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), b"c".to_vec()))), - a.clone(), - res, - ], - // Calls primitive 'c' so no tail. - None, - )); - } - evaluator.shrink_bodyform(&mut allocator, prog_args, env, res, false, None) - } -} - -struct Cons {} - -impl Cons { - fn create() -> Rc { - Rc::new(Cons {}) - } -} - -impl ExtensionFunction for Cons { - fn required_args(&self) -> Option { - Some(2) - } - - fn try_eval( - &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, - loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - if let (BodyForm::Quoted(a), BodyForm::Quoted(b)) = (args[0].borrow(), args[1].borrow()) { - Ok(Rc::new(BodyForm::Quoted(SExp::Cons( - loc.clone(), - Rc::new(a.clone()), - Rc::new(b.clone()), - )))) - } else { - Ok(body) - } - } -} - -struct First {} - -impl First { - fn create() -> Rc { - Rc::new(First {}) - } -} - -impl ExtensionFunction for First { - fn required_args(&self) -> Option { - Some(1) - } - - fn try_eval( - &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, - loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Cons(_, a, _)) = args[0].borrow() { - let a_borrowed: &SExp = a.borrow(); - Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) - } else if let BodyForm::Quoted(_) = args[0].borrow() { - Err(CompileErr(loc.clone(), "bad cons in first".to_string())) - } else { - Ok(body) - } - } -} - -struct Rest {} - -impl Rest { - fn create() -> Rc { - Rc::new(Rest {}) - } -} - -impl ExtensionFunction for Rest { - fn required_args(&self) -> Option { - Some(1) - } - - fn try_eval( - &self, - _evaluator: &Evaluator, - _prog_args: Rc, - _env: &HashMap, Rc>, - loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - if let BodyForm::Quoted(SExp::Cons(_, _, b)) = args[0].borrow() { - let a_borrowed: &SExp = b.borrow(); - Ok(Rc::new(BodyForm::Quoted(a_borrowed.clone()))) - } else if let BodyForm::Quoted(_) = args[0].borrow() { - Err(CompileErr(loc.clone(), "bad cons in rest".to_string())) - } else { - Ok(body) - } - } -} - -struct If {} - -impl If { - fn create() -> Rc { - Rc::new(If {}) - } -} - -impl ExtensionFunction for If { - fn want_interp(&self) -> bool { - false - } - - fn required_args(&self) -> Option { - Some(3) - } - - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - _loc: &Srcloc, - _name: &[u8], - args: &[Rc], - body: Rc, - ) -> Result, CompileErr> { - let mut allocator = Allocator::new(); - let cond_result = evaluator.shrink_bodyform( - &mut allocator, - prog_args.clone(), - env, - args[0].clone(), - false, - None, - )?; - - if let Ok(unquoted) = dequote(body.loc(), cond_result) { - if truthy(unquoted) { - evaluator.shrink_bodyform( - &mut allocator, - prog_args, - env, - args[1].clone(), - false, - None, - ) - } else { - evaluator.shrink_bodyform( - &mut allocator, - prog_args, - env, - args[2].clone(), - false, - None, - ) + ))) } - } else { - Ok(body.clone()) + _ => Err(CompileErr(args[0].loc(), "Not a string".to_string())), } } } @@ -750,14 +453,44 @@ pub struct PreprocessorExtension { extfuns: HashMap, Rc>, } +fn compile_to_run_err(e: CompileErr) -> RunFailure { + match e { + CompileErr(l, e) => RunFailure::RunErr(l, e), + } +} + +impl PrimOverride for PreprocessorExtension { + fn try_handle( + &self, + head: Rc, + _context: Rc, + tail: Rc, + ) -> Result>, RunFailure> { + eprintln!("running {head} {tail}"); + if let SExp::Atom(hl, head_atom) = head.borrow() { + let have_args: Vec> = + if let Some(args_list) = tail.proper_list() { + args_list.into_iter().map(Rc::new).collect() + } else { + return Ok(None); + }; + + if let Some(extension) = self.extfuns.get(head_atom) { + let res = extension.try_eval(&hl, &have_args) + .map_err(compile_to_run_err)?; + + eprintln!("res = {res}"); + return Ok(Some(res)); + } + } + + Ok(None) + } +} + impl PreprocessorExtension { pub fn new() -> Self { let extfuns = [ - (b"if".to_vec(), If::create()), - (b"list".to_vec(), List::create()), - (b"c".to_vec(), Cons::create()), - (b"f".to_vec(), First::create()), - (b"r".to_vec(), Rest::create()), (b"string?".to_vec(), StringQ::create()), (b"number?".to_vec(), NumberQ::create()), (b"symbol?".to_vec(), SymbolQ::create()), @@ -791,38 +524,3 @@ impl PreprocessorExtension { opts.set_prim_map(Rc::new(new_prim_map_cloned)) } } - -impl EvalExtension for PreprocessorExtension { - fn try_eval( - &self, - evaluator: &Evaluator, - prog_args: Rc, - env: &HashMap, Rc>, - loc: &Srcloc, - name: &[u8], - raw_args: &[Rc], - body: Rc, - ) -> Result>, CompileErr> { - if let Some(extfun) = self.extfuns.get(name) { - if let Some(n) = extfun.required_args() { - if raw_args.len() != n { - return Err(CompileErr( - loc.clone(), - format!("{} requires {} args", decode_string(name), n), - )); - } - } - - let args = if extfun.want_interp() { - reify_args(evaluator, prog_args.clone(), env, raw_args)? - } else { - raw_args.to_vec() - }; - Ok(Some(extfun.try_eval( - evaluator, prog_args, env, loc, name, &args, body, - )?)) - } else { - Ok(None) - } - } -} diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 0dc9042f6..6cff08790 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -10,12 +10,14 @@ use crate::classic::clvm_tools::clvmc::compile_clvm_text_maybe_opt; use crate::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; use crate::compiler::cldb::hex_to_modern_sexp; -use crate::compiler::clvm::convert_from_clvm_rs; +use crate::compiler::clvm; +use crate::compiler::clvm::{convert_from_clvm_rs, truthy}; +use crate::compiler::compiler::compile_from_compileform; use crate::compiler::comptypes::{ - BodyForm, CompileErr, CompilerOpts, HelperForm, IncludeDesc, IncludeProcessType, + BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, IncludeDesc, IncludeProcessType, }; use crate::compiler::dialect::KNOWN_DIALECTS; -use crate::compiler::evaluate::{create_argument_captures, dequote, ArgInputs, Evaluator}; +use crate::compiler::evaluate::{create_argument_captures, ArgInputs}; use crate::compiler::frontend::compile_helperform; use crate::compiler::preprocessor::macros::PreprocessorExtension; use crate::compiler::rename::rename_args_helperform; @@ -69,6 +71,22 @@ fn make_defmac_name(name: &[u8]) -> Vec { res } +fn nilize(v: Rc) -> Rc { + if let SExp::Cons(l,a,b) = v.borrow() { + let a_conv = nilize(a.clone()); + let b_conv = nilize(b.clone()); + if Rc::as_ptr(&a_conv) == Rc::as_ptr(&a) && Rc::as_ptr(&b_conv) == Rc::as_ptr(&b) { + v.clone() + } else { + Rc::new(SExp::Cons(l.clone(), a_conv, b_conv)) + } + } else if !truthy(v.clone()) { + Rc::new(SExp::Nil(v.loc())) + } else { + v + } +} + impl Preprocessor { pub fn new(opts: Rc) -> Self { let runner = Rc::new(DefaultProgramRunner::new()); @@ -278,29 +296,35 @@ impl Preprocessor { )?; let ppext = Rc::new(PreprocessorExtension::new()); - let mut eval = Evaluator::new( - ppext.enrich_prims(self.opts.clone()), + let extension: &PreprocessorExtension = ppext.borrow(); + let opts_prims = extension.enrich_prims(self.opts.clone()); + let new_program = CompileForm { + loc: body.loc(), + args: mdata.args.clone(), + include_forms: vec![], + helpers: self.helpers.clone(), + exp: mdata.body.clone(), + }; + let mut symbol_table = HashMap::new(); + let compiled_program = compile_from_compileform( + &mut allocator, self.runner.clone(), - self.helpers.clone(), - ); - eval.add_extension(ppext); - let res = eval.shrink_bodyform( + opts_prims.clone(), + new_program, + &mut symbol_table, + )?; + let res = clvm::run( &mut allocator, - mdata.args.clone(), - ¯o_arg_env, - mdata.body.clone(), - false, + self.runner.clone(), + opts_prims.prim_map(), + Rc::new(compiled_program), + args.clone(), + Some(extension), None, - )?; + ).map(nilize).map_err(|e| CompileErr::from(e))?; - if let Ok(unquoted) = dequote(body.loc(), res) { - return Ok(Some(unquoted)); - } else { - return Err(CompileErr( - body.loc(), - "Failed to fully evaluate macro".to_string(), - )); - } + eprintln!("macro {} {args} => {res}", decode_string(&name)); + return Ok(Some(res)); } } } diff --git a/src/compiler/runtypes.rs b/src/compiler/runtypes.rs index 720822337..c19d5cc45 100644 --- a/src/compiler/runtypes.rs +++ b/src/compiler/runtypes.rs @@ -1,6 +1,7 @@ use std::fmt::Display; use std::rc::Rc; +use crate::compiler::comptypes::CompileErr; use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; @@ -27,3 +28,12 @@ impl Display for RunFailure { Ok(()) } } + +impl From for CompileErr { + fn from(item: RunFailure) -> Self { + match item { + RunFailure::RunExn(l, s) => CompileErr(l.clone(), format!("Runtime exception: {s}")), + RunFailure::RunErr(l, s) => CompileErr(l.clone(), format!("Runtime error: {s}")), + } + } +} diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 8135428e1..93ef4c848 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -361,7 +361,7 @@ pub fn decode_string(v: &[u8]) -> String { return String::from_utf8_lossy(v).as_ref().to_string(); } -fn printable(a: &[u8]) -> bool { +pub fn printable(a: &[u8]) -> bool { for ch in a.iter() { if (*ch as char).is_control() || !(*ch as char).is_ascii() { return false; diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 9d8947227..4ada850c1 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -325,7 +325,7 @@ fn test_defmac_create_match_form() { (match X ((16 x y) (c 1 (+ x y))) ((3 () b c) c) - ((3 (q . 1) b c) b) + ((3 1 b c) b) (x x) ) ) From e96b7c8ef29835e57defdbb5ba4c56f5a1b88c56 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 10 Aug 2023 14:30:37 -0700 Subject: [PATCH 103/196] Start adding test material for a better wasm interface --- wasm/tests/clvm-tools-interface/.gitignore | 21 + .../clvm-tools-interface/babel.config.js | 7 + wasm/tests/clvm-tools-interface/package.json | 80 + .../scripts/getPackageJson.js | 25 + .../clvm-tools-interface/scripts/testMock.js | 1 + .../clvm-tools-interface/src/demo/index.ts | 8 + .../clvm-tools-interface/src/lib/image.png | Bin 0 -> 20753 bytes .../clvm-tools-interface/src/lib/index.css | 20 + .../clvm-tools-interface/src/lib/index.ts | 14 + .../src/lib/tests/index.test.ts | 12 + wasm/tests/clvm-tools-interface/tsconfig.json | 17 + .../webpack.config.demo.js | 47 + .../clvm-tools-interface/webpack.config.js | 71 + wasm/tests/clvm-tools-interface/yarn.lock | 6146 +++++++++++++++++ 14 files changed, 6469 insertions(+) create mode 100644 wasm/tests/clvm-tools-interface/.gitignore create mode 100644 wasm/tests/clvm-tools-interface/babel.config.js create mode 100644 wasm/tests/clvm-tools-interface/package.json create mode 100644 wasm/tests/clvm-tools-interface/scripts/getPackageJson.js create mode 100644 wasm/tests/clvm-tools-interface/scripts/testMock.js create mode 100644 wasm/tests/clvm-tools-interface/src/demo/index.ts create mode 100644 wasm/tests/clvm-tools-interface/src/lib/image.png create mode 100644 wasm/tests/clvm-tools-interface/src/lib/index.css create mode 100644 wasm/tests/clvm-tools-interface/src/lib/index.ts create mode 100644 wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts create mode 100644 wasm/tests/clvm-tools-interface/tsconfig.json create mode 100644 wasm/tests/clvm-tools-interface/webpack.config.demo.js create mode 100644 wasm/tests/clvm-tools-interface/webpack.config.js create mode 100644 wasm/tests/clvm-tools-interface/yarn.lock diff --git a/wasm/tests/clvm-tools-interface/.gitignore b/wasm/tests/clvm-tools-interface/.gitignore new file mode 100644 index 000000000..a6b9b35fa --- /dev/null +++ b/wasm/tests/clvm-tools-interface/.gitignore @@ -0,0 +1,21 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +.vscode + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/wasm/tests/clvm-tools-interface/babel.config.js b/wasm/tests/clvm-tools-interface/babel.config.js new file mode 100644 index 000000000..f60764c10 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/babel.config.js @@ -0,0 +1,7 @@ +module.exports = { + presets: [["@babel/env"]], + plugins: [ + ["@babel/plugin-proposal-class-properties"], + ["@babel/plugin-transform-typescript"], + ], +}; diff --git a/wasm/tests/clvm-tools-interface/package.json b/wasm/tests/clvm-tools-interface/package.json new file mode 100644 index 000000000..3fc737a5f --- /dev/null +++ b/wasm/tests/clvm-tools-interface/package.json @@ -0,0 +1,80 @@ +{ + "name": "clvm-tools-interface", + "version": "0.1.35", + "description": "Tests and extras for the clvm_tools_rs javascript interface", + "main": "build/index.js", + "types": "build/types/index.d.ts", + "scripts": { + "start": "webpack serve --config webpack.config.demo.js", + "build": "webpack && tsc", + "build:demo": "webpack --config webpack.config.demo.js", + "test": "jest", + "coverage": "npm run test -- --coverage", + "prepare": "npm run build", + "trypublish": "npm publish || true" + }, + "repository": { + "type": "git", + "url": "https://github.com/hodgef/ts-library-boilerplate-basic" + }, + "author": "Francisco Hodge (https://github.com/hodgef)", + "license": "MIT", + "bugs": { + "url": "https://github.com/hodgef/ts-library-boilerplate-basic/issues" + }, + "homepage": "https://github.com/hodgef/ts-library-boilerplate-basic", + "keywords": [ + "library", + "starter", + "es6" + ], + "devDependencies": { + "@babel/cli": "^7.22.9", + "@babel/core": "^7.22.10", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-transform-typescript": "^7.22.10", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.22.10", + "@types/jest": "^29.5.3", + "@typescript-eslint/eslint-plugin": "^4.33.0", + "@typescript-eslint/parser": "^4.33.0", + "babel-eslint": "^10.1.0", + "babel-loader": "^9.1.3", + "babel-preset-minify": "^0.5.2", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^5.0.1", + "eslint": "^7.32.0", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.3", + "jest": "^29.6.2", + "mini-css-extract-plugin": "^2.7.6", + "style-loader": "^3.3.2", + "terser-webpack-plugin": "^5.3.9", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "4.13.3" + }, + "jest": { + "moduleNameMapper": { + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/scripts/testMock.js", + "\\.(css|less)$": "/scripts/testMock.js" + }, + "moduleFileExtensions": [ + "web.js", + "js", + "web.ts", + "ts", + "web.tsx", + "tsx", + "json", + "web.jsx", + "jsx", + "node" + ] + }, + "dependencies": { + "bls-signatures": "^2.0.2" + } +} diff --git a/wasm/tests/clvm-tools-interface/scripts/getPackageJson.js b/wasm/tests/clvm-tools-interface/scripts/getPackageJson.js new file mode 100644 index 000000000..fe44d4b5d --- /dev/null +++ b/wasm/tests/clvm-tools-interface/scripts/getPackageJson.js @@ -0,0 +1,25 @@ +const fs = require('fs'); +const path = require('path'); + +/** + * A module to get package informations from package.json + * @module getPackageJson + * @param {...string} keys from package.json if no arguments passed it returns package.json content as object + * @returns {object} with given keys or content of package.json as object + */ + +/** + * Returns package info + */ +const getPackageJson = function(...args) { + const packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'))); + if (!args.length) { + return packageJSON; + } + return args.reduce((out, key) => { + out[key] = packageJSON[key]; + return out; + }, {}); +}; + +module.exports = getPackageJson; \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/scripts/testMock.js b/wasm/tests/clvm-tools-interface/scripts/testMock.js new file mode 100644 index 000000000..a09954537 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/scripts/testMock.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/src/demo/index.ts b/wasm/tests/clvm-tools-interface/src/demo/index.ts new file mode 100644 index 000000000..69b6174f7 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/src/demo/index.ts @@ -0,0 +1,8 @@ +import MyLibrary from "../lib"; +const myLibraryInstance = new MyLibrary(); + +document.querySelector("body").innerHTML = `

Hello World!

`; + +console.log("myLibraryInstance", myLibraryInstance); + +myLibraryInstance.myMethod(); \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/src/lib/image.png b/wasm/tests/clvm-tools-interface/src/lib/image.png new file mode 100644 index 0000000000000000000000000000000000000000..83b0b67c5792eb30050f5d14237ded0387c505e9 GIT binary patch literal 20753 zcmeFZXH-*N6gGJ2T|zHXReDzhsR^JU0)jvQ1wt2)F4DU+rCR_2X(BE3CcQV6F47?p zkX}MBfxujRXV#jTHEVv%pII~C_X7?jH~ZeR&pvza=h^$@tdqu==2UWmbw=}By`y5saSYyPezZ%fG$h@8tU`UZ}wk$#5L-CfuX1sI0WKVe|cZ#6WVqr_u?=N&cv7 zf9&$OYd;5l{xe70Ks(@=WNczkaWR|_7_Mk2tu=rj?wmYXZ)nM}PYpeiYqNez2%9i< zw?7;zt(OcH$&TeF<|v!-e{h&*Xl6S15;rzRHDQV{t+gj8tKAU0xD5QeSv7XkHnXtB z^Jr>a2<@-SU){FefG9++XJj0=HEWF)3u9X_%BB-qL)1P^_NnO#(C1MrDZf&X$j63o zk5VL(Zg=I?s3aew4asj0c7&DMoym_+*~|`Idd4{UdU~tuQ{6kgS^MoyUk81wMGE2# z6H}es`D5*mG2Crx!On6FZsgOsnDNmDOqguxj7s{^DF%94-ox3w-b!6(<%$OECI%)9 zFqbKr-_14bZt6GBo|5EOq77YIcYBewXzv03lPR4)qq+sR$f201){Dvd6*Z;d6>Wtl z0T;i$WP|*HXEU@xuT2+&^d}Bay+>T{5mH3clT!7^!P6QSJG9C+8lt#I-g--Tcihgt z{oA8ifLO6;i!>z9s;T^2iSL3#I`!kYAtDJ$QEq+|Cz`_e*|{^*Q5XdIJJ?C}j81+z z#h!D5Ry>Lp`2%%4K9Hlc`?C-6?w~Myc+FJWOb+XVt>@HN9JAMlXj z`D`L(3qLD{VH}yXRgk~7Xp<4VQK&u8DCMZeft>jPDb7#vv`^X~=)%PXi8@O%izIzYlMyH=Z2|6(WE zxft~dC$5}Wo^IjS>1mdK%+RJ279D=J(V)mAMjJ-lS?e&?ohi=m?qQ0_D4%`6DKBMd zO!-FTPmpZJN+d)OF-ceCLUGv=%{|$d#Cc?%7a#^$CUhK>qU*QrjuCh@TZp$0g?D&H zMrBdAxNoeU0^+0^yEo>mqq4rlbY{7lP+uz~HxJQl7@oV?X7%`6*Zz5qhbd>@sR?It z6^F}ik?GWYmAE>or~mj`Bt920pQP7CbfXLF;kba35$n;KSwN_b1<+YZFZ4Q&j3TO% zJ~>>TExu%liselrv(t8YerZIOyxck*8YP8^cap8zCetm_M`c^xgO!3@vXwUQLt6tSozGn!{PVny zPyYR=6V zz0VHUoW5f7X@Pf*yC2JbCHZU7c9iZkb?%dx>wN2$>lA$Ovqp@=Dv=lW>Dy1s=)CF! zJ7dZScTx@&;1%!uq8PRH%jpQJntu|i9#94K^l&FU*#$zY=!HVUU`yn^C)x{L;$txO zskR46z?+u24-KsR26(xYUy>NJ@x?Os_4JL|qi`8g_ksIKj0)#06hmg(T)|4@W?_ef zf@ls4v;5~&FFoyMweV*aPPv`}ENY>dn%+Cd!Z3#6>OS3-`SYfZyP!JAEP5}F6Q$Q2 z3>F`8U8%uwgwBpTMhr`M&7J;uMYTsLtzV6N5d{-C+x;52#i@CIlKwVxMc@c?;iG@4 zkI(h;)t><9UDoKqXl2racCS36=j3g~P8zeHJ_HJPt6L;-3=F9rFO@!6Q&Ubl%6)c& zHI0x{yH4*>X`2Qdcc&IZgU?k-+mqG0hAm?M7)^R}$0cZEdGi}Z@Y^Fh<|grNCVVFo zO6Q~gdF>QZ)kl7`1|fNh)C^vWH{A}0>V0q$;2cN;f|P-->FvN?#t-d4gnHGVZf?Tq zI-jjp1(esVZz2y!>60ngAD#TJW$@-OQP;t_KSx=l0&g5=o!;sRWkcTw!a&XIzceF6 zsFGGo>^Jq5GC>N%A*-&hos8o8B6S7w@Wl*xwl#K!h4zcD%=)h-=y;!D$8=ZY4}>ls z<n*Bnc2RYMAhV$Zs;m!(GM+ZeqNU{1gE?c z7}BGE<%r<5P0!4U#bLhhg_CfqUD{44%sU<>wv@>aT#zZwWSZPc`2(9z?wjgTC65t8 z_+0NP#-MqDT9{fFzky*Xmf*_#oSm21@0ZFICAYecRhbm<2+RI1WGF%jEE#luPF(8Z z!Mz2J(7U3@AVEBcj1KNj8YI;|l}h|!(pTXm5iGQ3e9X@(THW9J>x9ldVlqBDMVy}{ z!@!@e^3qT1nU8?`FRsFg{-tA^-Vn~beCAqtn`_^=9&4~v`@~DDYtM;wO(qkBexGs?2;sZggsfVMR{vUk^EU(3DgPL+PpKC+n!01RfwxS)7 zKZc3?Bj|WmdRc@XIW+S*_^~d{ajtqeNjG$S^a)^ZtchfAavuxItNT!!p|6SGF@&I zIv)4xq0_a|DZ`h1xjU(6-)#qDkb!x=7efI-2dPw03wl4hu2~xhJu*=7JY_Vemw;bg z+YH~#I|dFXp6@&QM(MdUNaS$M-x<{_AE=Jz2x>^>y6d9SNP&t}Jo`{w(DAb~W+k-K z0Y~j&>JlF^eA1Mlx7wN%0EQ`y#7C33%+NyogHWb0Z2hAr*?tA_6H1JDIt6w*V>`MI zA}WIFq}sYIG2<*Z8EqAsH$lzNK6kxWbw)+D*7+Xg&R4= z+8;fAP-%xZJljq2eT*AD?(J43w;0{pK1+mA*$n+<>sl)p)~+Dhn9Zj(`ndqP-gWO* zRQBZ{d?n1Jh}e&Ur*lJ*@Ug{hL(X_F8jBlfRH^FcA(ivM;bW~Y`vD>{qlBrq5VfaK z^^rVI0SoTvRE?9WX9a`x`_zx&@#$&W2`m?bd-)fJH5k2k(jY(<((3Q5EzfGm@cnam zW4_jCSmT-n8es+>Yu=6aaE_3r$)^a==6iOV#!(`y9857gwMI8%;e1}V6j#b@w1+-$ zgT6kmx3_Wl(K6Mp-seoeB78dF-F>9$&+IR}gfLT5jUOo7SEpQ&-M&D$n{KA(pU1}hc_NvW=ff<10CsOF)3y2{;DG z`--p#0|r)=$P5)GI%KHg-qf9(N7?qh!vx|%yA+e$jh+%+6q)HPVK98I8JOknd1fW& z>|`8a$isDa9b}pq)3e9oJlmR4_ICJOjLHSo>f8rx4Xy%4lSwn%XD<#5#WD^T2);*G z%u?J!ooWZ{R*59b{RxP|dA(%*QNkj9vq(AXcVD}2$)o5_h%V}UG7+orsS?ZAZbcq! zM5!Gpt);i5<8iQC*Ca%!WKn%)XL3%r&%#9AW$bSj6uj!H{x|O32av;9}JH?N5mUi9s5sy@wk9`?AVYpn}-o3-0U0Nd-sy8 zOPLVHVmK{ah`)dzNoRn^Q%D}8V6XdFc?RtcNxShz=40j63@iAZ>q^lT`v9f(7jghk zhu2bNRiDYf8@vZD(Y@1VAj?Oo_>IhGyZEp2oL?!G{U|J%{v}`){G~Im3I(|UUUj#L z!?2w9iMRBgGJeIk^Wx1xPy9NgrLRmz3c3owt@gV5EJBwuGW??4aoKDUTBN}b7lh&! zr_MT27vqL9lR$AkM&Oq1g6Z?UcSy+~8vLxkUMH ztoY%H9vvTCc^OCpREVQI_G^&AKwUwdd@csyx90>9qM`&E+$%pnQAOX(sHHU5tG$)l zcE5#Dls*nFNTRC{Xp}nU#-J0$^*rd>zv!iZ6=&b8U2M%D^h`abc;e&$&^TRbM1h}r z?|BQtNvKs`loyk~8PgRR)lx`w=2_xDFHN%JDZWsbvHrtD2)niW*Q+)2ubT@PQ9Zz% zZYhgk=k>kUa@|BPkT2-Q^TkHly5&v-%v_zi;vTT{X$w)*3rmV>KW2Hhxynzk4aa>L zc4sqjxDie{Kt-psY-Z0!%?YNV)?w`T4Kr{%~fmB-vFn|Ad>tA9=g44@D;;0jNuXjsViTo(;x0fJc{L%dvXQK9;|O&Z``m)=kS^eJan1q5Hg zb>cem__ANyn+6d6H2Lx9{+FE>-sq^dJo{_B92C&xVP5#5 z_H58oP>kkJ8}p)YV08%7QrNIGW@uZX0KDS!CoA5N4HFA`ztizM+y*5)ke2yz@vHO; zmtynR^l+FAQ9h48Xs#FPJD=#tf*&sTq5E$FrR z*UT2;d7U5nW!bZ8Mchf+IiVjTC@9@%CSbv}B=J~?#0eLO88d|Y zAY*Vz*zo6l|5dW$dxfSA5l2yu*Ocub?60$Q(huGa1qc--kY`C&(B=!J(TZT64XNME zd#YwX#%pSL8AkETlpWfGz&vGsx;>BkmSmdEH$jY*$R&MQMHLVFU0Fv4^!`kMc|~e^tzsPjn{^Ly*WL zp6NBAs<59GDQ6kZQubO;k58)zW4}LG@l?rk_1|~|^y2!F zFJ$4c;ha2s1KQZ`vOI;_F4cnoZN0u0wOi!oIs?3D(k$Mm}2=|nb_Byu|z zl$YVVeKr;e{ebhc(X#NFbU`1n_H_cxa*$3=g&-q-g*mq%?t`~X#(aL$y~tq3i6p`y z`I(`3qcLCkkizniR{^svBMLJM>>zp40<3S*%#l{*U$eOYF=8_5^X&K#xo=AnK(*d?#nb zT}B@m$cvZT7NhW6(CuqU{UusN`t)AmAc=~R@@M4y?)D)nk}MU9;nW=~1Kt$-pNqA^ z6u}+l|_|~W)!|;2-tneIs zJ1VyyqalRU?5N1biBmNEvKX{F17(%fa(c%%dhOH9Buber8?i|dc$9`Gd#8LJrkSN1 zzCorF8v!&nuxCd}tIC6PLDQ=_oZsJhY*!w$bUlYIr_@iU*m+&EdDHgj%l^az^wpD6 zm#$<2Z#MlwP!pO#KHdZJ5kc8%!(ixpcS%g(Dv^!;(L&L|rDYi@0{&ARwXF3sSrD77nHx`aFC&;QB!midz*rym~4rIacL?ZM< zc22qBiJ-cESpkjH-KfZbj7}1XBb+h_T|uV+4Ora`zX!AMKQ~*YCe(=o+N7rYyT&W_m5u`nZUNff6BSA-SX~2-@L8lM0WQ1quKW%z6vNQ#~DF zuq(IqBq*y~c(cJlbih0sn9O3AAeFUyIn4FdWcH_BL046_FsEIWs%vKjfm;jn;!9uCgE->P_! zQ1NXt{qG118*a%FcF2Q-ak2H z$3As4&^n41X7i&OYv*a)s24-RyPfbiWgDFe2JcP!vk0<`O1!c_Nr?S!tEYKg(`uIM87ZMoj7SCTL(-2AXO9ape~}kY(b+6L7RSxn$?yY)MOVsI zJr-*&f12#q>;Cca6B93+RS32xj_^UXUggInD0j3aoB(87LNWUGlsa#C`r3aPFt1|O3V5~v+{*V|bk1;7M zwkU)#SLwhHy@y=)a`w|AHpXvbBMtFo>?K}-TzqD+6nk5DiJkPamC~Ua@hX=(vEhz> z0cZX!dtUg6Tq`w?%tBqg@9wrp_Ek#xBuaA5aSrUcnm^>s ze%V%^{-VEmK#YwgX_ZK2Ji5p{eY>tTVP<;JPGz-_iQPU{8)7ogiaV~JGNy|=a1zp_ zlQnsG8Cl%5j$AtVpt7Uajo=J5zJO004swVkNjC&_w6@wlp83_Y7o2<`@{xJG#QLaS z=aJFgYuC8wGug;>Wb7nVMXb`1ESP@~Bu}glms~QC&OV1@-6Trce8XUQgIy$?fH^hK z-t(ybhXm;)N04VvrU`xsm;Y1LvtLXD9~XYbE#2d|m%nI2bz)goCYXHF-N<>w3#b+$ zv{vDyF-6`(1$fEx{q;^Xyl^ZpV^Mg z;hE>Iy)p>c@!c0boo9T+4qGGptl;3>3b`*1dlnX?(e#*$#ms=r9xjL@^7te2#7mF=bMs> zR0oIR<)7K{YS&e$$gtDfK2p7klU8;Nn^AE82a?h3QSh;JW5aanZ??=Ai2iJ%0#=HZ zI8zqK-s(Y0x5DjPAbRP!N9sGbEQFjvW06m8F6qwtF5VrRaXGJ8-_LJZB%%@zJt6Y9 z-83wR?uK_hGC}I3mQ<{*OLjb%T_>|wsV^|@d&hm`6U8(cAaa>%?4j>%1~NixeC$-byv&OTsy0W<(Vuh`FS+0k)C=K+#=hG>-ly#oTqDM= z=e%kORsAXCwr6an%wXo$rz%_deI?W!gWvqPr+rli|NH}w!KJ=0Q1P9^Z{c*EF7wRb zFo`;#9y6fWes$Jb)f;T?h$JQ>|NNr zS27?N6l^Jr{C!qDd0Y;VcCege_ZE4fkH?;Lu0q*&j1F}MzH&>p^>m9BHPV^fi+if9 zn?#_}JXy5i>lNSUxEvV5jP47-oGsNkUK3sZdn02pEssoTF9pQ1@89QFk_DUB4D;~| zQ=ipe9_$pzu7W(GcmXbloYXvUfwow`**j?=T)LAZxNzSBHvo< z?nyT*&oyIWRW?hv%&&ywbJf*RBu6TEZlAVq3cz8&J{<=CNa2xhKhfWvbhbUWn9*@; zYRtsb)>vj?cFa1aEPFNj;q!0q@ABn)T4V!SneyGf9u$J*^G{q?4-_vi|BT}(Q7yAS z&?{Up3oO@NIV+u*rTZHGMqc{=TQ5Mnr!N`R^bhX}>A!NgfN-qHzZfg zT*deKAwikQobF=`i19VR6cG$4FRJB*j}@=-YIkB|Je>${yi7~h?@2}>?K_l;=Wi7p zu}H+a|62pfPuOcOiC{5vPuBGd?Yqg-Zn8K}XXEF)w8Q|UdGtwl!cP8rh40eCc&|ATW=6AV%clTPE)SF@-4`ffZ%)*tpvD)2h=IP`0ylqP{6xarvt!Kdm^I9djF`=;M{C%1m$;i$0HGRr~x zwVp)xu4@iaH}Xl1PI4YkXL^lY%^KHVFE%Sn)n34 z^|Gz&%4L{bjr8c|7e@yNu936|?_6fG)?)I4huP#iSe+l1KPDU(!m1bFas+a-Ld$r8 z*VhydXOGpmbp){h9;KP-1aHXFypG8>d@mf43Gz8frd^8@UcpSN>zM6RiM7Gqx><+g zFPib|pKRO}XaJ>NWgZ>T*laxJTW|t<_BUQ9$D(cQ7cEHw>HX&FxzC6D7py4*W4tnN zo>fBexmMfrTTZraX|$uP>E!{(-}MjbIyu!^#SRZ#f25W607#4tpYeKw0g11p=Az05Wj0ZXR`~8w0 zoP`Mz(sodB5XC{qrq=4Rwl@EgEU0I|_RN{M`R2Augu@eM3-VWQLx1XQHk?kc<1W|v zkZAv%>p2n|Ds;Yhxe(qE1+c>au>xFA{!7vNL_zb-p^)&0HKLrd>qhydPXz4kNc9BA8Myc9=u~|No3CIFee280IB!I!gd-G z1n^rAq{YrL*|$jnEQIg);4ZiQU0l%K?Puf$KR>*U9XNhoE)Z>3+p`yH_<~=v9fXQY zThbRshbvxaNpkNizJ9}b8ibyyPZA-(0oT}rR-PND0&Ar~nK@{mLY^_h2mFHcdH$st zKa}nC*^>N95bJk;c%+GzTx-JQBjqmt{5HR~00NtlGpoR@3R}M*&EWT4_F{6h3c2s` zv-b52Buyu8c^w8pW%Hd4Ur7+m=zA z)T${UU&SEk9k^tMyMKtPZF-S6KpHYag08Q@?%3`@(Gdv_x^O+F19tq$@{d}I8maWJ zzSyVMhw*}i@3nfj-Ed+kgRrQBrq75bTm;P2rQ>qU?zzizhH-6a({8uE2TjA4jQPhb zh#Ybhp;Zx3t9dl$S&pI3krs8+W)3ikulg!!T)m*?AX$!L7Au}$_u^!YpvnwJi5Pp5R z@QeomRp%7uQoH!4MhnFCJYdQo=Y^BLpR0^ui>IO`SCPZ#l4Zi4hZQ3JF&kGH<1wcw z$hlR#qMDzMS&PwVbKjjCq;8p#C z@23Z4E!h(~yz&MGl0Pl(`%gxciwLAb4RgrMhi>_p1ZN{RWQ9+C?|m4V6b$BlRd*vmnK z2m+Iv-}W<|$e!O*NZG8siM_0*7>{1K>z2? zgq;ghgj(G9d&KQcKC>&w9oCSCh6sX^JD&dBS^2McSWM0pToV>u;yS_+nwbNKJN4Pw z)_Z@7YrGH%d$*|CYCCYhT*fZ-d8-bys3?w=C2IfS^X$$>=N3=N*SPo=?{Bhu!;529 z+VbcrtJpJKlThgM-)0xfAAZz^Ae>D9T;S!W<;kSCdy41YFPqx=G=C$&?|I133tLMu zif802!FB!^5OPg{);+jl$@JA{hTT`P@FFc5;+gTV>9cfLM`VB+Hy=LNvM3?-Ri*JS z1FR^VLq1zt=S0SL{p}OT!KofPWdK9D# z-GYl0rMeByUi*AD7sZARP9aDoEy09|iguu#K*TG>(W~`j;scj~^Rz!@J){wpurx@8 z3+d1{y1~$a6oX>_7Q9$r<~{jx^NrKsc;ek z+HEW})!W^@d86!jNPLq47>LwiMmz@Y^C@Fepcfl1hM0i9qRP4UY(YCV;u1z=@;EK4 zT>j?9s6oNY7uTQTB_!gKg8D^Khpp0XcQBjV*k06q)mG}xq~Rg~DQVlqq($rAkHSPZ zuY)GMzuS6l@NG5Pm5ZD}WICTEEd{!X3&^)`ae90`d$|i(FuHTe2ya*|q z;(bSx=q3etKL+2;uw3(l6+N@+Ry^WW>!ybm*E&ouC%F`Jb2X9oJoz%hx*R`KFKh7k zcN7uA4!DJh{J?IpBM)lj!=ZPV_NPp3K>Zzg+ih$sEJ0jzzNRW*#H*u;G<-gi5cWz` zm}us>P)${@c6FTZV$V1gNx@_g^Ky;g=_v6;S|rK;%+OzOff(&?hAUG z@Vw#HfEkC)gKKtmRO0tmw8GcAA8m$ysHDw1E;Qf8cULouXNpKLfO~xD?cFf8%WD>E zUlc7OOwELlgSdlhq=M}ZLyR>zMM3?7rtJnHZu(?hRNyjl|_;u#zG}9t<#lOs^0SP%x^_HFrBW+g9WdlGXP;q06l^GSkJAG?UP* zqK^r`1>AUx_TIU!oFzl5*Ls8-xnw=x2aLqMNQ2%Ry-hR}I2;2!>sLlF(YL4g$M*ZV zi}@c>hEwwdKF)hRB8Lb05e8YkA{wu?#dPS`EJ3kmd4YJ8YNVXbFH(D$E(jUHCCD7w z@BgA%5nYx|pWU8R7xV7)86r!ES@kOPB!$`|T2v+nH*UJL4Sm1N}xE!#sxI#5)#WEnfQgtDCkO0vLR97 zu9}^;!JFyvaOezEuEcgQ!x$iixVN3si+-_o@;WBaOasXyhrBNfQJG(SE8VFpF3Shp z(6CUS918e5e+3c8l{vE@ufxTK!z=-7jLzm^&blpN>HV&=B6Y&_vPFoQ5vP22>~^^V zD8x#Dxf`sN*FXT=Y>@AN^h+JVT_pAt*UA!Z0a$PNQwEm0q&_c0Ks$d)4qUw6#vc2O zc=L*eJ~NVlY1YIHKRmfc&rIIg2WkPaN_B9ZI?zg=Y(G)0k6NX}-5>0cxP!!2{H5SB z&h8y5>yFB7rf8vmzDgW40gVeZOU3Y(IE)kp^}H7$0HLPdmtN6l7TMxWF;}ErqPPXV z0jb)fVp8&UZPI$pQ~d7+qyg9T;U0RMyH#f0LpuyFCt5LEUT#=R^rt&y9KPxdI{Csx zIYw8_bzwKNZ}1CKQD}5U%nHlKcu-pykk%;gSk*JZ3!_*cwuUmjQ7~O(zhAk3J|y0}5w@NYP6xX4 z&nN2fpc{rEOIkvKF|bN|)T>4(znxTm;4M}+R;zYlyBz=s{rh_^xxXJb}U zKGJOElsh~@%#?)vENv)tK_Ue`ToUb%M=unM7@E8gf`r{1%vW@YkbMYrJ3fc41H2& zZ0x0{(fHwSub`}uJK*(GV5v5tCtJ(tJ%j&(JAwp!>0=+gI5_;DyW#%_?ce@C9trq= zLkY7yyKCu1$o0BVs{Sc^IeL&qX>PD*jl=^NDa$-5_-dqo3=o2Y&OJN`IKbu!Vc-CS z(*gg#d9(4BeDgnl;qklu>c9zqJUJIQ{7)rhfF-1j^P6Xq+O|lf?5Fmmxex79 zlmlP)C*{M3O1D5F*61J|721OSV7ypyIQP}>L!8q+M!!csm6}`raJYu&jENT3Ih6t( zl9zlw8Hb-$e>uWLkZZ#iCY)Z3Tz5UOPkml8ykY}(&Cqvd?NrS?aJx*+E1d8fZYYhf zA5NJr0rN!T4bG|jDOr@{z~Jxeh7*V9(EAk9Yx3iX;Hvjxcu+%g5BD-+&{{pc2F$-> zJ>s2AC+36XWOr7+J9cROwR#;~Z+zTnFX~T{s=jA6^MkfL&;GIWRW40>;FBMJ7~Zv; zmuLSia`BGVi5_mJF2f;}H%zq;Y=N^nquA}D2A)P|n$0U8@@ASYy+LbTi@-?DM|(8= zAUe2dg4v3P!`gsX(**p1{AFEY#)=7}GP>}wL$Et8UFzWJ5K?Tk#T8GSblzP&&=Z#$ zom3gth?F3GxlhyJCEv0#*bO0N4o0NHdWS9Y6SBNktWu`7brQ$MLeDyg+J?c59~vl4 zgU`T=@^9*_2!C8sj9o+qn{)Z5;WLg}aO(sq`<#s{PB51uk7Pfz?~??3lr$(Ub>xa$ zJpE)vkuKAMWmRE-P^y(#{aO5BQAWKu$WFer2B=r& zOE-da!K-0qcshp*k-OcGS^L#UgO(+J1wBVL1I+JF=5DRo^3A8JYvTnAvg~6fPzpsL#>8HK{f%Pfs9ktd!ze z`p6HQu4Ovh0y`&A_a3~uIaq>q{)J?fqLeDwkfqd`T$=RCDc$gy1?1U-@?^dVflZi4 z0fftz&BwbJMjo}+hA!Vx-t2d)CR44n+_A+rgT6ANT6b8{oCxy)w!jV&H)a}y7WS=K z|H|&Cz`zst@_|4z934Ss=x+4yuef`nIVjmBE61qIaktb??Py$pdQhC?iT9-gbHacO20^;RgJ)LsiR zxnq6y;k>~LrO~E5eKyiiN?m(0C)KJV$Cv+fk%M*##0k+G^I(rib#WKD*MK5ezPUP- z5aTt$_v@G}xXTkvr>eCM)r+ka{{~a3o?LUkfs!yaEPnn?l3glKiy;#MOQ7X^2j$F3uKT+e zQrrnv6xUylprA~@C`k9lZRl1LCk>w~G{^FbO+KPD8V3t(M|G_$V>9L^TOQ@zZXAaO zV8`iqd=5@vufj#wEc_(Jw@2doXPgM~13a^HGjDA^mz?zWm<>=}jV#=G#!JjpyrF4V zpsa^}?6HA@x&NZ=*%8>~>FU$$)9iq;WeK$ON3;N~?}95|4>**}JLytO#ElxZSSJ z0I@FE0N!ket!GMkNl+h4M!7|z$N|c(ZL&0hTg;{E^Qg54XeII7LS#^nKAuuW!?j@E zbm3{?>kA9h!nkK^c2g72rVkA6*>;cv!|&AbAmZsy|GV`0)unSv``ikR9z{V5zsmex z&Xhi+Qw6dpoJBj%`@tG?9y#gWs15MSC3@s9e%2J5ONEQ{`*D}9B=sDl#rxu31VFIQ zXxsH=TaF1jWH8rFQz965mYsXYr{A|yqm7UIv>b!$_~u)TrGY4aB?2x6hM!BRzZccQ zA=P&(uzb~lZ$$XUzk>Jp^#C|<&>GdG^t4QT$T{#n5d-kEw0n(3-yuBpiC4fAVNP*r04ZsX3U7x|tZ} z7O-mZ0~4W%yubqxuM{8i&dC(MmI~CaxF2wDP#=Cs0qRix`7W{bPdpZJ`cZ?+m^C6o z0$25+v^uk=cY*S_ZyV^^$41Wn!lKfOvzBWIlTm5<>9UHE&_K~6W%-dWDaS7asm&{| zEF|dw|MmGHJ0Q}#Mxo3F{IS6rT?R_*etDjG^H;i*o@FD%?{brM84-#Ycm`Su6U4f7 zg2#NHo#~?8Ps7rp7a3Clsn=_n^!pk?i_I9Rym+pOaGf%)V&TB##)}_H;q7& z{>a8bYW}NicJP#P4y`3@ka>3n_$wPO4{__=*4`Di= zyt9#eB-3ezheMwbF!8izk+kE!p4`M{--Zw5eLj~fwoM2I>u*dX`Cu}f$UJH z12?{GoncK&3PcM%4wWsDEf%);VM}@VIPEX7UYggxCrHQ^?QJUydz8i4{32%QGb)ZT zAlQIbgh1|&eVB`I638>`b;DR#SNXVqXpr&coe7fQ(oo*Tx(h8IvsN z%YSBRqrS*CtjYnm?^IOs5#RTSOe&1E7=@RT1 zkvBB9YT=tJ3D>Ycar}YT_IEu~ag~S=w=N5Ok(=R7)a|8P-_B@R&G`HUtJXmcV>;^Q zv37V_fhT@j!z{BDyi{RL7D)XlI8@n_$)t6TfBlSmbMxdYYe!}}oiA-{QIPN@ewK!l z;`OuA1fuWijAKx%*FLM-6L`a4IiRW`F8$x6M#p8Zg**#~jzq0<0>o=85S42pY-C4vnl@xj0M3{|RJqb%pD{7=|i<1NLGwerul z1o4chV!k~2?7yECsYfyzO0{cCeikBxgE-;KU4;T^3zbc7Q|D{D+M|;BwzGWPpQa5K zuGw0!IgShm<|x~>bZWdPmBQAKk1O~nI2o|Shoj{z@`ZcTbe;9v96!56S}k}eHx@YMqMIw+cGdiX{&YhG%PSuaE|PrDpp?pG)*Ai2p^yw_ zykxX_o(}7c79OT$Czf(Giy}o@a_|X{OU^F@$$#Xfb``c2?lIA!KcK`ym;8+*q%b2p zt(;pYQ>d9Q@Hg&z#P!d=8|-bwmF5RGYYO)o;6~HqA6KyzQ&>zHnojVAK>_PFBky3( z39|r`91-mozsi^(ukt4VJNO-Qo`5;>zV>Ui_v!~tO&)pnSBe3*X|R8_o)H_^lTy(; zT4FMdaHDDuzW@5VUxI)Qr=#$*-~+)#1UOQ<@yA^se8d)hDfTi4&oWa`3s;)_7ff$7 z6T;l4lFhS%EGV}}%5ORTy7e)Zlv~e44f|xw6tK2iU|%WF%7wHg{Qb|~HauLI0RU2T z^}PVJYw|#pR?}mUw zY^dM)RwQ0W-oMyHfrR=QKyR7=_lyN2hdKUvF(y8IH5QkDp-ADiJ|Z zTl4SwII7jXtr%RHo3uyUa747w`8?3qK*+{3@=&IuT3v;0OJCCrGr84onA;&rO z`R8+v0Y9@V>@6OR=xqZJfCIzO|8GEZXLRID~y>2wgS z`=L(fm{9IuMSxy6J*U3TEdjePC{`Wg_U!UkX6Ec9~yz7!BK-5Fzv#pBV^(04p z@S7J%vw(TgqDNWs#idsv=wq2{lk&-(AweRe`}22Jp(va+*lFU%<5)n9Z+;sO0^{yr zpKv`+tQP$jWIpD%h#6%|&Nnd%x?u~jPc`mgA|4s77zH1Kk3+sd;rfiJ=%3h3ox3|j zwMS4C`y(1f7e!A@y)a5`e)jA#aK~Sukui%dFBq?X3Z2>V)fYQ;s_CEV`FZ!AwYaBz zYz^pFH3|FF>RhRMt)8I+&l$#QIWa32QxlwrcVqnr?wpfhiUdX1QsF1F3Ohf9nk|9x z`81-o&+K)VKkMV3Q&YV#^TQphExODI!^xOx@Ut#T3~_gOv-*06(9?mkBTOy+_J?h@ zfv-w24$KWYZn7FDbk6V3$C43G70$iNO!gHRSmn?MSPUGBTgKG*#(-6!L*q1LS*E8w zK{MgP)y4+N2vu?iORbP;4>#c@NpNo4}NT6JXQy`snOX#@0b5Y%-lGaaa&hY9V2hk2+uWh3P)x( zUoNNC3ujUW-8?TTzg0zh0rcMo2*t%OajQ0T(%#d{BmK^)|6-7RxRulom7pRtwF&>h z;ES2#mE(&(cn&hthg@1o`R;H&^em@?Gnj=GoX9FBU~QnM8cfNM!N2V9*z-#k5FwCT zr`zDZM6EyXF77BNnx}3%0Qp++od2*Xo(e58XgVz4;%$<8B;Z2}Zo*;V9Iuqtr(o?y zA1`Gz}~GZ)#!*+V&ZIhop+`#aZz{*MHbU`V2Ul6by2g%PRm+| zKJXp*&0V)^T!=Ss(ua% z2er`KC83G#3M3 zbN#Z(S3!@yeFMq2=<1w`cJ0`vZ}-UJG%?Pk?H)0pynW8nt;P z7c35=*Hy%_F2dVN256f_!^Brx{D$D1XTvf95#OgB$}-Qfj-y8G!B=Y^PMRG`COnsV zg`C-#nuGV~I(`LR&KIqGvvz09;aXK$iAm=(Hbh*+(@Afw*_!AAlp$4jVR*{_`Q+@) z;o^TLwns0>w2dv%Qdh}xomI)?=Y{~oJfH`|Qw~ZIzmc)se}z`b`ORd)U?C7vVD&xd z3nAIEJTcL>7gGQ0d)$N#Te!iCVzgex(JN6Ro~l5oG(QQ(5cGA^*@#O&gG>MarI{;#YU+x@2@RM4 z3KTFX4oi`>Y>{0kNh8Q0L9r|W3?S1|j0h3KW(X#bYI5qCRDJ}!6)$q1DEt-=sF|ug3 zEE+B}+UzSDi1Wny;^Cshqfv=doR!TcNP%sO*ei3wZm=kNb^s4K-we|k@|%jeh$YWuG(!oI-)xH4!Zeb6=r*eq`8G1wB^7OxZ%e0omufD&2_jc$nXJSaN-J z#`{e0mTtLf*Wx&B-xh9GBZd+uT1Fso6zFv#Vbsm~WC+y99((GC1!{G=K1RNs?VW^U z>hzjKqyAoy00^lB1Xyb84v~sYaJZ}cf{R6uInuO6GxSmkGra5Mv5ojPMRIS=!0<7B3jVQ9sdf4um0TOM6;t|xvQEz> z+8zFs_u_e<#aAXDM|9#Z)yGo<%^aA<5e!6LsAl#ubn?ubmt>2i|D%FW^G3JckURPjaE;e^~)c|X(v$W0BT4Ae+LLrll) zLKyN2(_et>OsRi%u(|@k^@~tUCH37!FV})G_R>-!Nj_D#R@*Oiw`~?bCDMLb?B2qM z0kUUYv*?E$c)%BE#B`?UeV0ooH}W#zDeMC;E2qVi&p8J9nDnhNi6h;c!pDB(;#{eQP)Ih-^qCIS=6NHQlG! zRXsMehTAH!bmr|!?_{m5PIo+dx-vyxlBb4Z43YMZ&mLVPV2ZnT)c_=KXc&H*cu17c?roeG!DZ67Md>Du%5ao?ayghxr z?l6f|^Ij6W{mXP#hP5~i0)G031r?w@({4_oolb$bTqhZGN9C(sflVJ#I`;`(wACZr zE`w{yaJ_-6^*Pn;%r(wV?XP4^yECI>M;>xE(o$q9KHO^; zbtjm4jddw{MsL~ot6Kd5;^SQoy1BPe5|7g#nn7GgPjNJ(=A%-9*NG0J80Mm-SLrJ} zecd@*&7f|`Y907*bBzUU2jPFEfo|bqsZ zX{^B@qbfa64YS4koT`ARO;S)3KnSLKkI$dyayLE$qI^7{(<;oJRQP+)9 zX^t4nd?}=%)BdSr_Xv!-KZ2|bhR1kK2;&#nhiFo>J1D-5>YN#&xW%J13$M7GJG+lv zs~yrPc+4YFscW|p{D4;*$#vsWidt~V5uwQM6K^ud#0qwcZz;56Er_NYqFEy89WpNz zFPrs!vR)rA_ZNx$Vo;RIoWUQMTHVxU4=`ZQrr{`N1P@uB_z literal 0 HcmV?d00001 diff --git a/wasm/tests/clvm-tools-interface/src/lib/index.css b/wasm/tests/clvm-tools-interface/src/lib/index.css new file mode 100644 index 000000000..55c846f49 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/src/lib/index.css @@ -0,0 +1,20 @@ +html, +body { + margin: 0; + padding: 0; + font-family: sans-serif; + height: 100%; +} + +h1 { + margin: 0; + font-weight: 300; +} + +body { + background: url("image.png") no-repeat 98% 2%; + background-size: 300px; + padding: 20px; + height: 100%; + box-sizing: border-box; +} diff --git a/wasm/tests/clvm-tools-interface/src/lib/index.ts b/wasm/tests/clvm-tools-interface/src/lib/index.ts new file mode 100644 index 000000000..0225e997d --- /dev/null +++ b/wasm/tests/clvm-tools-interface/src/lib/index.ts @@ -0,0 +1,14 @@ +import "./index.css"; + +class MyLibrary { + constructor() { + console.log("Library constructor loaded"); + } + + myMethod = (): boolean => { + console.log("Library method fired"); + return true; + }; +} + +export default MyLibrary; diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts new file mode 100644 index 000000000..991911cf7 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -0,0 +1,12 @@ +import MyLibrary from '../index'; +import * as bls_loader from 'bls-signatures'; + +it('Runs without crashing', () => { + new MyLibrary(); +}); + +it('Has BLS signatures support', async () => { + let bls = await bls_loader.default(); + let g1element = new bls.G1Element(); + console.log(g1element.serialize()); +}); diff --git a/wasm/tests/clvm-tools-interface/tsconfig.json b/wasm/tests/clvm-tools-interface/tsconfig.json new file mode 100644 index 000000000..639484c09 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "noImplicitAny": true, + "outDir": "build/types", + "module": "esnext", + "target": "es5", + "allowJs": true, + "sourceMap": true, + "declaration": true, + "emitDeclarationOnly": true, + "suppressImplicitAnyIndexErrors": true, + "lib": ["es2018", "dom"], + "moduleResolution": "node", + }, + "include": ["src/lib"], + "exclude": ["src/lib/**/tests"], +} \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/webpack.config.demo.js b/wasm/tests/clvm-tools-interface/webpack.config.demo.js new file mode 100644 index 000000000..1627bd603 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/webpack.config.demo.js @@ -0,0 +1,47 @@ +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + mode: "development", + devtool: 'cheap-module-source-map', + entry: './src/demo/index.ts', + output: { + filename: 'index.js' + }, + optimization: { + minimize: false, + }, + devServer: { + open: true, + hot: true, + host: "localhost", + port: 9000 + }, + module: { + rules: [ + { + test: /\.(m|j|t)s$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader' + } + }, + { + test: /\.(sa|sc|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + { loader: "css-loader", options: { sourceMap: true } }, + ], + } + ] + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: 'css/index.css' + }), + new HtmlWebpackPlugin(), + ], + resolve: { + extensions: ['.ts', '.js', '.json'] + } +}; \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/webpack.config.js b/wasm/tests/clvm-tools-interface/webpack.config.js new file mode 100644 index 000000000..c050382c7 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/webpack.config.js @@ -0,0 +1,71 @@ +const path = require('path'); +const webpack = require('webpack'); +const TerserPlugin = require('terser-webpack-plugin'); +const getPackageJson = require('./scripts/getPackageJson'); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); + +const { + version, + name, + license, + repository, + author, +} = getPackageJson('version', 'name', 'license', 'repository', 'author'); + +const banner = ` + ${name} v${version} + ${repository.url} + + Copyright (c) ${author.replace(/ *<[^)]*> */g, " ")} and project contributors. + + This source code is licensed under the ${license} license found in the + LICENSE file in the root directory of this source tree. +`; + +module.exports = { + mode: "production", + devtool: 'source-map', + entry: './src/lib/index.ts', + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'build'), + library: "MyLibrary", + libraryTarget: 'umd', + clean: true + }, + optimization: { + minimize: true, + minimizer: [ + new TerserPlugin({ extractComments: false }), + new CssMinimizerPlugin() + ], + }, + module: { + rules: [ + { + test: /\.(m|j|t)s$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader' + } + }, + { + test: /\.(sa|sc|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + { loader: "css-loader", options: { sourceMap: true } }, + ], + } + ] + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: 'css/index.css' + }), + new webpack.BannerPlugin(banner) + ], + resolve: { + extensions: ['.ts', '.js', '.json'] + } +}; diff --git a/wasm/tests/clvm-tools-interface/yarn.lock b/wasm/tests/clvm-tools-interface/yarn.lock new file mode 100644 index 000000000..162a52399 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/yarn.lock @@ -0,0 +1,6146 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/cli@^7.22.9": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.22.10.tgz#25e4bbd8d0a0d8b4b389e1b5e2d7a238bd4c1b75" + integrity sha512-rM9ZMmaII630zGvtMtQ3P4GyHs28CHLYE9apLG7L8TgaSqcfoIGrlLSLsh4Q8kDTdZQQEXZm1M0nQtOvU/2heg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + commander "^4.0.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.1.0" + glob "^7.2.0" + make-dir "^2.1.0" + slash "^2.0.0" + optionalDependencies: + "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" + chokidar "^3.4.0" + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.10", "@babel/code-frame@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3" + integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA== + dependencies: + "@babel/highlight" "^7.22.10" + chalk "^2.4.2" + +"@babel/compat-data@^7.22.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.10.tgz#aad442c7bcd1582252cb4576747ace35bc122f35" + integrity sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.10" + "@babel/generator" "^7.22.10" + "@babel/helper-compilation-targets" "^7.22.10" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.10" + "@babel/parser" "^7.22.10" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.10" + "@babel/types" "^7.22.10" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.1" + +"@babel/generator@^7.22.10", "@babel/generator@^7.7.2": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.10.tgz#c92254361f398e160645ac58831069707382b722" + integrity sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A== + dependencies: + "@babel/types" "^7.22.10" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz#573e735937e99ea75ea30788b57eb52fab7468c9" + integrity sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ== + dependencies: + "@babel/types" "^7.22.10" + +"@babel/helper-compilation-targets@^7.22.10", "@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024" + integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.22.10", "@babel/helper-create-class-features-plugin@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.10.tgz#dd2612d59eac45588021ac3d6fa976d08f4e95a3" + integrity sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz#9d8e61a8d9366fe66198f57c40565663de0825f6" + integrity sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + regexpu-core "^5.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz#82c825cadeeeee7aad237618ebbe8fa1710015d7" + integrity sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-member-expression-to-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2" + integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-remap-async-to-generator@^7.22.5", "@babel/helper-remap-async-to-generator@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz#53a25b7484e722d7efb9c350c75c032d4628de82" + integrity sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-wrap-function" "^7.22.9" + +"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779" + integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + +"@babel/helper-wrap-function@^7.22.9": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz#d845e043880ed0b8c18bd194a12005cb16d2f614" + integrity sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ== + dependencies: + "@babel/helper-function-name" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.10" + +"@babel/helpers@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.10.tgz#ae6005c539dfbcb5cd71fb51bfc8a52ba63bc37a" + integrity sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.10" + "@babel/types" "^7.22.10" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7" + integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.10", "@babel/parser@^7.22.5", "@babel/parser@^7.7.0": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.10.tgz#e37634f9a12a1716136c44624ef54283cabd3f55" + integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e" + integrity sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz#fef09f9499b1f1c930da8a0c419db42167d792ca" + integrity sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.5" + +"@babel/plugin-proposal-class-properties@^7.16.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98" + integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-attributes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz#ab840248d834410b829f569f5262b9e517555ecb" + integrity sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.22.5", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz#aac8d383b062c5072c647a31ef990c1d0af90272" + integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" + integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-async-generator-functions@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.10.tgz#45946cd17f915b10e65c29b8ed18a0a50fc648c8" + integrity sha512-eueE8lvKVzq5wIObKK/7dvoeKJ+xc6TvRn6aysIjS6pSCeLy7S/eVi7pEQknZqyqvzaNKdDtem8nUNTBgDVR2g== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz#c7a85f44e46f8952f6d27fe57c2ed3cc084c3775" + integrity sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ== + dependencies: + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + +"@babel/plugin-transform-block-scoped-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" + integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-block-scoping@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz#88a1dccc3383899eb5e660534a76a22ecee64faa" + integrity sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz#97a56e31ad8c9dc06a0b3710ce7803d5a48cca77" + integrity sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-static-block@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz#3e40c46f048403472d6f4183116d5e46b1bff5ba" + integrity sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz#e04d7d804ed5b8501311293d1a0e6d43e94c3363" + integrity sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" + integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/template" "^7.22.5" + +"@babel/plugin-transform-destructuring@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz#38e2273814a58c810b6c34ea293be4973c4eb5e2" + integrity sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dotall-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz#dbb4f0e45766eb544e193fb00e65a1dd3b2a4165" + integrity sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-duplicate-keys@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz#b6e6428d9416f5f0bba19c70d1e6e7e0b88ab285" + integrity sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dynamic-import@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz#d6908a8916a810468c4edff73b5b75bda6ad393e" + integrity sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz#402432ad544a1f9a480da865fda26be653e48f6a" + integrity sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-export-namespace-from@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz#57c41cb1d0613d22f548fddd8b288eedb9973a5b" + integrity sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz#ab1b8a200a8f990137aff9a084f8de4099ab173f" + integrity sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" + integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== + dependencies: + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-json-strings@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz#14b64352fdf7e1f737eed68de1a1468bd2a77ec0" + integrity sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" + integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-logical-assignment-operators@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz#66ae5f068fd5a9a5dc570df16f56c2a8462a9d6c" + integrity sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" + integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-amd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz#4e045f55dcf98afd00f85691a68fc0780704f526" + integrity sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-commonjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz#7d9875908d19b8c0536085af7b053fd5bd651bfa" + integrity sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-modules-systemjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz#18c31410b5e579a0092638f95c896c2a98a5d496" + integrity sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ== + dependencies: + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/plugin-transform-modules-umd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz#4694ae40a87b1745e3775b6a7fe96400315d4f98" + integrity sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" + integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-new-target@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz#1b248acea54ce44ea06dfd37247ba089fcf9758d" + integrity sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz#f8872c65776e0b552e0849d7596cddd416c3e381" + integrity sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz#57226a2ed9e512b9b446517ab6fa2d17abb83f58" + integrity sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz#9686dc3447df4753b0b2a2fae7e8bc33cdc1f2e1" + integrity sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ== + dependencies: + "@babel/compat-data" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.22.5" + +"@babel/plugin-transform-object-super@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" + integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + +"@babel/plugin-transform-optional-catch-binding@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz#842080be3076703be0eaf32ead6ac8174edee333" + integrity sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.22.10", "@babel/plugin-transform-optional-chaining@^7.22.5": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.10.tgz#076d28a7e074392e840d4ae587d83445bac0372a" + integrity sha512-MMkQqZAZ+MGj+jGTG3OTuhKeBpNcO+0oCEbrGNEaOmiEn+1MzRyQlYsruGiU8RTK3zV6XwrVJTmwiDOyYK6J9g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18" + integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-methods@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz#21c8af791f76674420a147ae62e9935d790f8722" + integrity sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-property-in-object@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz#07a77f28cbb251546a43d175a1dda4cf3ef83e32" + integrity sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" + integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-regenerator@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz#8ceef3bd7375c4db7652878b0241b2be5d0c3cca" + integrity sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + regenerator-transform "^0.15.2" + +"@babel/plugin-transform-reserved-words@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz#832cd35b81c287c4bcd09ce03e22199641f964fb" + integrity sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-shorthand-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" + integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" + integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + +"@babel/plugin-transform-sticky-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz#295aba1595bfc8197abd02eae5fc288c0deb26aa" + integrity sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-template-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" + integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typeof-symbol@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz#5e2ba478da4b603af8673ff7c54f75a97b716b34" + integrity sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typescript@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.10.tgz#aadd98fab871f0bb5717bcc24c31aaaa455af923" + integrity sha512-7++c8I/ymsDo4QQBAgbraXLzIM6jmfao11KgIBEYZRReWzNWH9NtNgJcyrZiXsOPh523FQm6LfpLyy/U5fn46A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.10" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-typescript" "^7.22.5" + +"@babel/plugin-transform-unicode-escapes@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz#c723f380f40a2b2f57a62df24c9005834c8616d9" + integrity sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-property-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz#098898f74d5c1e86660dc112057b2d11227f1c81" + integrity sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz#ce7e7bb3ef208c4ff67e02a22816656256d7a183" + integrity sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-sets-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz#77788060e511b708ffc7d42fdfbc5b37c3004e91" + integrity sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/polyfill@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96" + integrity sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + +"@babel/preset-env@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.10.tgz#3263b9fe2c8823d191d28e61eac60a79f9ce8a0f" + integrity sha512-riHpLb1drNkpLlocmSyEg4oYJIQFeXAK/d7rI6mbD0XsvoTOOweXDmQPG/ErxsEhWk3rl3Q/3F6RFQlVFS8m0A== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.10" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.5" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.22.5" + "@babel/plugin-syntax-import-attributes" "^7.22.5" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.22.5" + "@babel/plugin-transform-async-generator-functions" "^7.22.10" + "@babel/plugin-transform-async-to-generator" "^7.22.5" + "@babel/plugin-transform-block-scoped-functions" "^7.22.5" + "@babel/plugin-transform-block-scoping" "^7.22.10" + "@babel/plugin-transform-class-properties" "^7.22.5" + "@babel/plugin-transform-class-static-block" "^7.22.5" + "@babel/plugin-transform-classes" "^7.22.6" + "@babel/plugin-transform-computed-properties" "^7.22.5" + "@babel/plugin-transform-destructuring" "^7.22.10" + "@babel/plugin-transform-dotall-regex" "^7.22.5" + "@babel/plugin-transform-duplicate-keys" "^7.22.5" + "@babel/plugin-transform-dynamic-import" "^7.22.5" + "@babel/plugin-transform-exponentiation-operator" "^7.22.5" + "@babel/plugin-transform-export-namespace-from" "^7.22.5" + "@babel/plugin-transform-for-of" "^7.22.5" + "@babel/plugin-transform-function-name" "^7.22.5" + "@babel/plugin-transform-json-strings" "^7.22.5" + "@babel/plugin-transform-literals" "^7.22.5" + "@babel/plugin-transform-logical-assignment-operators" "^7.22.5" + "@babel/plugin-transform-member-expression-literals" "^7.22.5" + "@babel/plugin-transform-modules-amd" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-modules-systemjs" "^7.22.5" + "@babel/plugin-transform-modules-umd" "^7.22.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" + "@babel/plugin-transform-new-target" "^7.22.5" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.5" + "@babel/plugin-transform-numeric-separator" "^7.22.5" + "@babel/plugin-transform-object-rest-spread" "^7.22.5" + "@babel/plugin-transform-object-super" "^7.22.5" + "@babel/plugin-transform-optional-catch-binding" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.10" + "@babel/plugin-transform-parameters" "^7.22.5" + "@babel/plugin-transform-private-methods" "^7.22.5" + "@babel/plugin-transform-private-property-in-object" "^7.22.5" + "@babel/plugin-transform-property-literals" "^7.22.5" + "@babel/plugin-transform-regenerator" "^7.22.10" + "@babel/plugin-transform-reserved-words" "^7.22.5" + "@babel/plugin-transform-shorthand-properties" "^7.22.5" + "@babel/plugin-transform-spread" "^7.22.5" + "@babel/plugin-transform-sticky-regex" "^7.22.5" + "@babel/plugin-transform-template-literals" "^7.22.5" + "@babel/plugin-transform-typeof-symbol" "^7.22.5" + "@babel/plugin-transform-unicode-escapes" "^7.22.10" + "@babel/plugin-transform-unicode-property-regex" "^7.22.5" + "@babel/plugin-transform-unicode-regex" "^7.22.5" + "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" + "@babel/preset-modules" "0.1.6-no-external-plugins" + "@babel/types" "^7.22.10" + babel-plugin-polyfill-corejs2 "^0.4.5" + babel-plugin-polyfill-corejs3 "^0.8.3" + babel-plugin-polyfill-regenerator "^0.5.2" + core-js-compat "^3.31.0" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== + +"@babel/runtime@^7.8.4": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682" + integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.22.5", "@babel/template@^7.3.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/traverse@^7.22.10", "@babel/traverse@^7.7.0": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.10.tgz#20252acb240e746d27c2e82b4484f199cf8141aa" + integrity sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig== + dependencies: + "@babel/code-frame" "^7.22.10" + "@babel/generator" "^7.22.10" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.10" + "@babel/types" "^7.22.10" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.10", "@babel/types@^7.22.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03" + integrity sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.2.tgz#bf1d4101347c23e07c029a1b1ae07d550f5cc541" + integrity sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + slash "^3.0.0" + +"@jest/core@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.2.tgz#6f2d1dbe8aa0265fcd4fb8082ae1952f148209c8" + integrity sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg== + dependencies: + "@jest/console" "^29.6.2" + "@jest/reporters" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.5.0" + jest-config "^29.6.2" + jest-haste-map "^29.6.2" + jest-message-util "^29.6.2" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-resolve-dependencies "^29.6.2" + jest-runner "^29.6.2" + jest-runtime "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + jest-watcher "^29.6.2" + micromatch "^4.0.4" + pretty-format "^29.6.2" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.2.tgz#794c0f769d85e7553439d107d3f43186dc6874a9" + integrity sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q== + dependencies: + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.2" + +"@jest/expect-utils@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.2.tgz#1b97f290d0185d264dd9fdec7567a14a38a90534" + integrity sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg== + dependencies: + jest-get-type "^29.4.3" + +"@jest/expect@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.2.tgz#5a2ad58bb345165d9ce0a1845bbf873c480a4b28" + integrity sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg== + dependencies: + expect "^29.6.2" + jest-snapshot "^29.6.2" + +"@jest/fake-timers@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.2.tgz#fe9d43c5e4b1b901168fe6f46f861b3e652a2df4" + integrity sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA== + dependencies: + "@jest/types" "^29.6.1" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.6.2" + jest-mock "^29.6.2" + jest-util "^29.6.2" + +"@jest/globals@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.2.tgz#74af81b9249122cc46f1eb25793617eec69bf21a" + integrity sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/expect" "^29.6.2" + "@jest/types" "^29.6.1" + jest-mock "^29.6.2" + +"@jest/reporters@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.2.tgz#524afe1d76da33d31309c2c4a2c8062d0c48780a" + integrity sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + jest-worker "^29.6.2" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040" + integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1" + integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.2.tgz#fdd11583cd1608e4db3114e8f0cce277bf7a32ed" + integrity sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw== + dependencies: + "@jest/console" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz#585eff07a68dd75225a7eacf319780cb9f6b9bf4" + integrity sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw== + dependencies: + "@jest/test-result" "^29.6.2" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + slash "^3.0.0" + +"@jest/transform@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.2.tgz#522901ebbb211af08835bc3bcdf765ab778094e3" + integrity sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-regex-util "^29.4.3" + jest-util "^29.6.2" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.1": + version "29.6.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2" + integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== + dependencies: + "@jest/schemas" "^29.6.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" + integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + +"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": + version "2.1.8-no-fsevents.3" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" + integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/babel__core@^7.1.14": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" + integrity sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.1.tgz#dd6f1d2411ae677dcb2db008c962598be31d6acf" + integrity sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg== + dependencies: + "@babel/types" "^7.20.7" + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" + integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + dependencies: + "@types/node" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#9fd20b3974bdc2bcd4ac6567e2e0f6885cb2cf41" + integrity sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.44.2" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.2.tgz#0d21c505f98a89b8dd4d37fa162b09da6089199a" + integrity sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": + version "4.17.35" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" + integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/graceful-fs@^4.1.3": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + dependencies: + "@types/node" "*" + +"@types/html-minifier-terser@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== + +"@types/http-errors@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" + integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== + +"@types/http-proxy@^1.17.8": + version "1.17.11" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.11.tgz#0ca21949a5588d55ac2b659b69035c84bd5da293" + integrity sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.5.3": + version "29.5.3" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.3.tgz#7a35dc0044ffb8b56325c6802a4781a626b05777" + integrity sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/mime@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + +"@types/node@*": + version "20.4.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.9.tgz#c7164e0f8d3f12dfae336af0b1f7fdec8c6b204f" + integrity sha512-8e2HYcg7ohnTUbHk8focoklEQYvemQmu9M/f43DZVx43kHn0tE3BY/6gSDxS7k0SprtS0NHvj+L80cGLnoOUcQ== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/send@*": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301" + integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-index@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" + integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a" + integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw== + dependencies: + "@types/http-errors" "*" + "@types/mime" "*" + "@types/node" "*" + +"@types/sockjs@^0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" + integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + dependencies: + "@types/node" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/ws@^8.5.1": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== + dependencies: + "@types/node" "*" + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== + dependencies: + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== + dependencies: + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== + +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-opt" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/wast-printer" "1.11.6" + +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== + +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== + +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.0.1, ajv@^8.9.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +babel-eslint@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +babel-helper-evaluate-path@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c" + integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA== + +babel-helper-flip-expressions@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz#3696736a128ac18bc25254b5f40a22ceb3c1d3fd" + integrity sha512-rSrkRW4YQ2ETCWww9gbsWk4N0x1BOtln349Tk0dlCS90oT68WMLyGR7WvaMp3eAnsVrCqdUtC19lo1avyGPejA== + +babel-helper-is-nodes-equiv@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684" + integrity sha512-ri/nsMFVRqXn7IyT5qW4/hIAGQxuYUFHa3qsxmPtbk6spZQcYlyDogfVpNm2XYOslH/ULS4VEJGUqQX5u7ACQw== + +babel-helper-is-void-0@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz#7d9c01b4561e7b95dbda0f6eee48f5b60e67313e" + integrity sha512-07rBV0xPRM3TM5NVJEOQEkECX3qnHDjaIbFvWYPv+T1ajpUiVLiqTfC+MmiZxY5KOL/Ec08vJdJD9kZiP9UkUg== + +babel-helper-mark-eval-scopes@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562" + integrity sha512-+d/mXPP33bhgHkdVOiPkmYoeXJ+rXRWi7OdhwpyseIqOS8CmzHQXHUp/+/Qr8baXsT0kjGpMHHofHs6C3cskdA== + +babel-helper-remove-or-void@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60" + integrity sha512-eYNceYtcGKpifHDir62gHJadVXdg9fAhuZEXiRQnJJ4Yi4oUTpqpNY//1pM4nVyjjDMPYaC2xSf0I+9IqVzwdA== + +babel-helper-to-multiple-sequence-expressions@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d" + integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA== + +babel-jest@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.2.tgz#cada0a59e07f5acaeb11cbae7e3ba92aec9c1126" + integrity sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A== + dependencies: + "@jest/transform" "^29.6.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.5.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-loader@^9.1.3: + version "9.1.3" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-9.1.3.tgz#3d0e01b4e69760cc694ee306fe16d358aa1c6f9a" + integrity sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw== + dependencies: + find-cache-dir "^4.0.0" + schema-utils "^4.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-minify-builtins@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b" + integrity sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag== + +babel-plugin-minify-constant-folding@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz#f84bc8dbf6a561e5e350ff95ae216b0ad5515b6e" + integrity sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ== + dependencies: + babel-helper-evaluate-path "^0.5.0" + +babel-plugin-minify-dead-code-elimination@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.2.tgz#f386ceec77a80cc4e76022a04c21b7d68e0aa5eb" + integrity sha512-krq9Lwi0QIzyAlcNBXTL4usqUvevB4BzktdEsb8srcXC1AaYqRJiAQw6vdKdJSaXbz6snBvziGr6ch/aoRCfpA== + dependencies: + babel-helper-evaluate-path "^0.5.0" + babel-helper-mark-eval-scopes "^0.4.3" + babel-helper-remove-or-void "^0.4.3" + lodash "^4.17.11" + +babel-plugin-minify-flip-comparisons@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz#00ca870cb8f13b45c038b3c1ebc0f227293c965a" + integrity sha512-8hNwgLVeJzpeLVOVArag2DfTkbKodzOHU7+gAZ8mGBFGPQHK6uXVpg3jh5I/F6gfi5Q5usWU2OKcstn1YbAV7A== + dependencies: + babel-helper-is-void-0 "^0.4.3" + +babel-plugin-minify-guarded-expressions@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz#818960f64cc08aee9d6c75bec6da974c4d621135" + integrity sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA== + dependencies: + babel-helper-evaluate-path "^0.5.0" + babel-helper-flip-expressions "^0.4.3" + +babel-plugin-minify-infinity@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz#dfb876a1b08a06576384ef3f92e653ba607b39ca" + integrity sha512-X0ictxCk8y+NvIf+bZ1HJPbVZKMlPku3lgYxPmIp62Dp8wdtbMLSekczty3MzvUOlrk5xzWYpBpQprXUjDRyMA== + +babel-plugin-minify-mangle-names@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.1.tgz#3dfba7f4e649ff37a767542ea0d1093bee3bb155" + integrity sha512-8KMichAOae2FHlipjNDTo2wz97MdEb2Q0jrn4NIRXzHH7SJ3c5TaNNBkeTHbk9WUsMnqpNUx949ugM9NFWewzw== + dependencies: + babel-helper-mark-eval-scopes "^0.4.3" + +babel-plugin-minify-numeric-literals@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz#8e4fd561c79f7801286ff60e8c5fd9deee93c0bc" + integrity sha512-5D54hvs9YVuCknfWywq0eaYDt7qYxlNwCqW9Ipm/kYeS9gYhJd0Rr/Pm2WhHKJ8DC6aIlDdqSBODSthabLSX3A== + +babel-plugin-minify-replace@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz#d3e2c9946c9096c070efc96761ce288ec5c3f71c" + integrity sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q== + +babel-plugin-minify-simplify@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz#f21613c8b95af3450a2ca71502fdbd91793c8d6a" + integrity sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A== + dependencies: + babel-helper-evaluate-path "^0.5.0" + babel-helper-flip-expressions "^0.4.3" + babel-helper-is-nodes-equiv "^0.0.1" + babel-helper-to-multiple-sequence-expressions "^0.5.0" + +babel-plugin-minify-type-constructors@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz#1bc6f15b87f7ab1085d42b330b717657a2156500" + integrity sha512-4ADB0irJ/6BeXWHubjCJmrPbzhxDgjphBMjIjxCc25n4NGJ00NsYqwYt+F/OvE9RXx8KaSW7cJvp+iZX436tnQ== + dependencies: + babel-helper-is-void-0 "^0.4.3" + +babel-plugin-polyfill-corejs2@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz#8097b4cb4af5b64a1d11332b6fb72ef5e64a054c" + integrity sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.4.2" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz#b4f719d0ad9bb8e0c23e3e630c0c8ec6dd7a1c52" + integrity sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.2" + core-js-compat "^3.31.0" + +babel-plugin-polyfill-regenerator@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz#80d0f3e1098c080c8b5a65f41e9427af692dc326" + integrity sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.2" + +babel-plugin-transform-inline-consecutive-adds@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz#323d47a3ea63a83a7ac3c811ae8e6941faf2b0d1" + integrity sha512-8D104wbzzI5RlxeVPYeQb9QsUyepiH1rAO5hpPpQ6NPRgQLpIVwkS/Nbx944pm4K8Z+rx7CgjPsFACz/VCBN0Q== + +babel-plugin-transform-member-expression-literals@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf" + integrity sha512-Xq9/Rarpj+bjOZSl1nBbZYETsNEDDJSrb6Plb1sS3/36FukWFLLRysgecva5KZECjUJTrJoQqjJgtWToaflk5Q== + +babel-plugin-transform-merge-sibling-variables@^6.9.5: + version "6.9.5" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.5.tgz#0b2faa9e027ef47d4e7502f77cd1a7f3a6dfbc7b" + integrity sha512-xj/KrWi6/uP+DrD844h66Qh2cZN++iugEIgH8QcIxhmZZPNP6VpOE9b4gP2FFW39xDAY43kCmYMM6U0QNKN8fw== + +babel-plugin-transform-minify-booleans@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198" + integrity sha512-9pW9ePng6DZpzGPalcrULuhSCcauGAbn8AeU3bE34HcDkGm8Ldt0ysjGkyb64f0K3T5ilV4mriayOVv5fg0ASA== + +babel-plugin-transform-property-literals@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39" + integrity sha512-Pf8JHTjTPxecqVyL6KSwD/hxGpoTZjiEgV7nCx0KFQsJYM0nuuoCajbg09KRmZWeZbJ5NGTySABYv8b/hY1eEA== + dependencies: + esutils "^2.0.2" + +babel-plugin-transform-regexp-constructors@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz#58b7775b63afcf33328fae9a5f88fbd4fb0b4965" + integrity sha512-JjymDyEyRNhAoNFp09y/xGwYVYzT2nWTGrBrWaL6eCg2m+B24qH2jR0AA8V8GzKJTgC8NW6joJmc6nabvWBD/g== + +babel-plugin-transform-remove-console@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780" + integrity sha512-88blrUrMX3SPiGkT1GnvVY8E/7A+k6oj3MNvUtTIxJflFzXTw1bHkuJ/y039ouhFMp2prRn5cQGzokViYi1dsg== + +babel-plugin-transform-remove-debugger@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2" + integrity sha512-Kd+eTBYlXfwoFzisburVwrngsrz4xh9I0ppoJnU/qlLysxVBRgI4Pj+dk3X8F5tDiehp3hhP8oarRMT9v2Z3lw== + +babel-plugin-transform-remove-undefined@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz#80208b31225766c630c97fa2d288952056ea22dd" + integrity sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ== + dependencies: + babel-helper-evaluate-path "^0.5.0" + +babel-plugin-transform-simplify-comparison-operators@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9" + integrity sha512-GLInxhGAQWJ9YIdjwF6dAFlmh4U+kN8pL6Big7nkDzHoZcaDQOtBm28atEhQJq6m9GpAovbiGEShKqXv4BSp0A== + +babel-plugin-transform-undefined-to-void@^6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280" + integrity sha512-D2UbwxawEY1xVc9svYAUZQM2xarwSNXue2qDIx6CeV2EuMGaes/0su78zlIDIAgE7BvnMw4UpmSo9fDy+znghg== + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== + dependencies: + babel-plugin-jest-hoist "^29.5.0" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-minify@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.2.tgz#4d5be8b1c21d126ac403a3fd002d8b5fb7bb3c34" + integrity sha512-v4GL+kk0TfovbRIKZnC3HPbu2cAGmPAby7BsOmuPdMJfHV+4FVdsGXTH/OOGQRKYdjemBuL1+MsE6mobobhe9w== + dependencies: + babel-plugin-minify-builtins "^0.5.0" + babel-plugin-minify-constant-folding "^0.5.0" + babel-plugin-minify-dead-code-elimination "^0.5.2" + babel-plugin-minify-flip-comparisons "^0.4.3" + babel-plugin-minify-guarded-expressions "^0.4.4" + babel-plugin-minify-infinity "^0.4.3" + babel-plugin-minify-mangle-names "^0.5.1" + babel-plugin-minify-numeric-literals "^0.4.3" + babel-plugin-minify-replace "^0.5.0" + babel-plugin-minify-simplify "^0.5.1" + babel-plugin-minify-type-constructors "^0.4.3" + babel-plugin-transform-inline-consecutive-adds "^0.4.3" + babel-plugin-transform-member-expression-literals "^6.9.4" + babel-plugin-transform-merge-sibling-variables "^6.9.5" + babel-plugin-transform-minify-booleans "^6.9.4" + babel-plugin-transform-property-literals "^6.9.4" + babel-plugin-transform-regexp-constructors "^0.4.3" + babel-plugin-transform-remove-console "^6.9.4" + babel-plugin-transform-remove-debugger "^6.9.4" + babel-plugin-transform-remove-undefined "^0.5.0" + babel-plugin-transform-simplify-comparison-operators "^6.9.4" + babel-plugin-transform-undefined-to-void "^6.9.4" + lodash "^4.17.11" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +binascii@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/binascii/-/binascii-0.0.2.tgz#a7f8a8801dbccf8b1756b743daa0fee9e2d9e0ee" + integrity sha512-rA2CrUl1+6yKrn+XgLs8Hdy18OER1UW146nM+ixzhQXDY+Bd3ySkyIJGwF2a4I45JwbvF1mDL/nWkqBwpOcdBA== + +bls-signatures@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bls-signatures/-/bls-signatures-2.0.2.tgz#a02cde31876d56dd4fb3c12b4e0b042a1b090a46" + integrity sha512-f60Oh1HRUfumYykCHaCzVRJKEXC2VlN+4YKl58fsFpovpx6/M023GdeK1sJqTH1eXFLqaERiCCPGWOhoubYtlA== + dependencies: + binascii "0.0.2" + +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +bonjour-service@^1.0.11: + version "1.1.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.1.tgz#960948fa0e0153f5d26743ab15baf8e33752c135" + integrity sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg== + dependencies: + array-flatten "^2.1.2" + dns-equal "^1.0.0" + fast-deep-equal "^3.1.3" + multicast-dns "^7.2.5" + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.21.4, browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001517: + version "1.0.30001519" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601" + integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^3.4.0, chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + +clean-css@^5.2.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224" + integrity sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww== + dependencies: + source-map "~0.6.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colord@^2.9.1: + version "2.9.3" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" + integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== + +colorette@^2.0.10, colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +common-path-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" + integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^1.1.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +core-js-compat@^3.31.0: + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.0.tgz#f41574b6893ab15ddb0ac1693681bd56c8550a90" + integrity sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw== + dependencies: + browserslist "^4.21.9" + +core-js@^2.6.5: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-declaration-sorter@^6.3.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" + integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g== + +css-loader@^6.8.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88" + integrity sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g== + dependencies: + icss-utils "^5.1.0" + postcss "^8.4.21" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.3" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.2.0" + semver "^7.3.8" + +css-minimizer-webpack-plugin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz#33effe662edb1a0bf08ad633c32fa75d0f7ec565" + integrity sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + cssnano "^6.0.1" + jest-worker "^29.4.3" + postcss "^8.4.24" + schema-utils "^4.0.1" + serialize-javascript "^6.0.1" + +css-select@^4.1.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== + dependencies: + boolbase "^1.0.0" + css-what "^6.0.1" + domhandler "^4.3.1" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-tree@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" + integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== + dependencies: + mdn-data "2.0.30" + source-map-js "^1.0.1" + +css-tree@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.2.1.tgz#36115d382d60afd271e377f9c5f67d02bd48c032" + integrity sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA== + dependencies: + mdn-data "2.0.28" + source-map-js "^1.0.1" + +css-what@^6.0.1, css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz#2a93247140d214ddb9f46bc6a3562fa9177fe301" + integrity sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ== + dependencies: + css-declaration-sorter "^6.3.1" + cssnano-utils "^4.0.0" + postcss-calc "^9.0.0" + postcss-colormin "^6.0.0" + postcss-convert-values "^6.0.0" + postcss-discard-comments "^6.0.0" + postcss-discard-duplicates "^6.0.0" + postcss-discard-empty "^6.0.0" + postcss-discard-overridden "^6.0.0" + postcss-merge-longhand "^6.0.0" + postcss-merge-rules "^6.0.1" + postcss-minify-font-values "^6.0.0" + postcss-minify-gradients "^6.0.0" + postcss-minify-params "^6.0.0" + postcss-minify-selectors "^6.0.0" + postcss-normalize-charset "^6.0.0" + postcss-normalize-display-values "^6.0.0" + postcss-normalize-positions "^6.0.0" + postcss-normalize-repeat-style "^6.0.0" + postcss-normalize-string "^6.0.0" + postcss-normalize-timing-functions "^6.0.0" + postcss-normalize-unicode "^6.0.0" + postcss-normalize-url "^6.0.0" + postcss-normalize-whitespace "^6.0.0" + postcss-ordered-values "^6.0.0" + postcss-reduce-initial "^6.0.0" + postcss-reduce-transforms "^6.0.0" + postcss-svgo "^6.0.0" + postcss-unique-selectors "^6.0.0" + +cssnano-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-4.0.0.tgz#d1da885ec04003ab19505ff0e62e029708d36b08" + integrity sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw== + +cssnano@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-6.0.1.tgz#87c38c4cd47049c735ab756d7e77ac3ca855c008" + integrity sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg== + dependencies: + cssnano-preset-default "^6.0.1" + lilconfig "^2.1.0" + +csso@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.5.tgz#f9b7fe6cc6ac0b7d90781bb16d5e9874303e2ca6" + integrity sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ== + dependencies: + css-tree "~2.2.0" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== + +dns-packet@^5.2.2: + version "5.6.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.0.tgz#2202c947845c7a63c23ece58f2f70ff6ab4c2f7d" + integrity sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-serializer@^1.0.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== + dependencies: + domelementtype "^2.2.0" + +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +domutils@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.477: + version "1.4.490" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz#d99286f6e915667fa18ea4554def1aa60eb4d5f1" + integrity sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +enhanced-resolve@^5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +enquirer@^2.3.5: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^4.2.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +envinfo@^7.7.3: + version "7.10.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.10.0.tgz#55146e3909cc5fe63c22da63fb15b05aeac35b13" + integrity sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-module-lexer@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" + integrity sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@^7.32.0: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.2.tgz#7b08e83eba18ddc4a2cf62b5f2d1918f5cd84521" + integrity sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA== + dependencies: + "@jest/expect-utils" "^29.6.2" + "@types/node" "*" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + +express@^4.17.3: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-cache-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-4.0.0.tgz#a30ee0448f81a3990708f6453633c733e2f6eec2" + integrity sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg== + dependencies: + common-path-prefix "^3.0.0" + pkg-dir "^7.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-6.3.0.tgz#2abab3d3280b2dc7ac10199ef324c4e002c8c790" + integrity sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw== + dependencies: + locate-path "^7.1.0" + path-exists "^5.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.0.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-monkey@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.4.tgz#ee8c1b53d3fe8bb7e5d2c5c5dfc0168afdd2f747" + integrity sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ== + +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.3: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061" + integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-minifier-terser@^6.0.2: + version "6.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" + integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== + dependencies: + camel-case "^4.1.2" + clean-css "^5.2.2" + commander "^8.3.0" + he "^1.2.0" + param-case "^3.0.4" + relateurl "^0.2.7" + terser "^5.10.0" + +html-webpack-plugin@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz#72270f4a78e222b5825b296e5e3e1328ad525a3e" + integrity sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg== + dependencies: + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" + tapable "^2.0.0" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-middleware@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" + integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== + dependencies: + "@types/http-proxy" "^1.17.8" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.8, ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" + integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== + dependencies: + has "^1.0.3" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.2.tgz#1e6ffca60151ac66cad63fce34f443f6b5bb4258" + integrity sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/expect" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.6.2" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-runtime "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + p-limit "^3.1.0" + pretty-format "^29.6.2" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.2.tgz#edb381763398d1a292cd1b636a98bfa5644b8fda" + integrity sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q== + dependencies: + "@jest/core" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.2.tgz#c68723f06b31ca5e63030686e604727d406cd7c3" + integrity sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.6.2" + "@jest/types" "^29.6.1" + babel-jest "^29.6.2" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.6.2" + jest-environment-node "^29.6.2" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-runner "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.6.2" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.2.tgz#c36001e5543e82a0805051d3ceac32e6825c1c46" + integrity sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.2.tgz#c9e4b340bcbe838c73adf46b76817b15712d02ce" + integrity sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw== + dependencies: + "@jest/types" "^29.6.1" + chalk "^4.0.0" + jest-get-type "^29.4.3" + jest-util "^29.6.2" + pretty-format "^29.6.2" + +jest-environment-node@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.2.tgz#a9ea2cabff39b08eca14ccb32c8ceb924c8bb1ad" + integrity sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.2" + jest-util "^29.6.2" + +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + +jest-haste-map@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.2.tgz#298c25ea5255cfad8b723179d4295cf3a50a70d1" + integrity sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA== + dependencies: + "@jest/types" "^29.6.1" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.6.2" + jest-worker "^29.6.2" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz#e2b307fee78cab091c37858a98c7e1d73cdf5b38" + integrity sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ== + dependencies: + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-matcher-utils@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz#39de0be2baca7a64eacb27291f0bd834fea3a535" + integrity sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ== + dependencies: + chalk "^4.0.0" + jest-diff "^29.6.2" + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-message-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.2.tgz#af7adc2209c552f3f5ae31e77cf0a261f23dc2bb" + integrity sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.6.2" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.2.tgz#ef9c9b4d38c34a2ad61010a021866dad41ce5e00" + integrity sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-util "^29.6.2" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + +jest-resolve-dependencies@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz#36435269b6672c256bcc85fb384872c134cc4cf2" + integrity sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w== + dependencies: + jest-regex-util "^29.4.3" + jest-snapshot "^29.6.2" + +jest-resolve@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.2.tgz#f18405fe4b50159b7b6d85e81f6a524d22afb838" + integrity sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-pnp-resolver "^1.2.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.2.tgz#89e8e32a8fef24781a7c4c49cd1cb6358ac7fc01" + integrity sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w== + dependencies: + "@jest/console" "^29.6.2" + "@jest/environment" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.4.3" + jest-environment-node "^29.6.2" + jest-haste-map "^29.6.2" + jest-leak-detector "^29.6.2" + jest-message-util "^29.6.2" + jest-resolve "^29.6.2" + jest-runtime "^29.6.2" + jest-util "^29.6.2" + jest-watcher "^29.6.2" + jest-worker "^29.6.2" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.2.tgz#692f25e387f982e89ab83270e684a9786248e545" + integrity sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/globals" "^29.6.2" + "@jest/source-map" "^29.6.0" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-message-util "^29.6.2" + jest-mock "^29.6.2" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.2.tgz#9b431b561a83f2bdfe041e1cab8a6becdb01af9c" + integrity sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.6.2" + graceful-fs "^4.2.9" + jest-diff "^29.6.2" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + natural-compare "^1.4.0" + pretty-format "^29.6.2" + semver "^7.5.3" + +jest-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d" + integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.2.tgz#25d972af35b2415b83b1373baf1a47bb266c1082" + integrity sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg== + dependencies: + "@jest/types" "^29.6.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + leven "^3.1.0" + pretty-format "^29.6.2" + +jest-watcher@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.2.tgz#77c224674f0620d9f6643c4cfca186d8893ca088" + integrity sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA== + dependencies: + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.6.2" + string-length "^4.0.1" + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^29.4.3, jest-worker@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" + integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== + dependencies: + "@types/node" "*" + jest-util "^29.6.2" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.2.tgz#3bd55b9fd46a161b2edbdf5f1d1bd0d1eab76c42" + integrity sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg== + dependencies: + "@jest/core" "^29.6.2" + "@jest/types" "^29.6.1" + import-local "^3.0.2" + jest-cli "^29.6.2" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.1.2, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +launch-editor@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" + integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== + dependencies: + picocolors "^1.0.0" + shell-quote "^1.7.3" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" + integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== + dependencies: + p-locate "^6.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + +lodash@^4.17.11, lodash@^4.17.20, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +mdn-data@2.0.28: + version "2.0.28" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba" + integrity sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g== + +mdn-data@2.0.30: + version "2.0.30" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" + integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.4.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" + integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== + dependencies: + fs-monkey "^1.0.4" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-css-extract-plugin@^2.7.6: + version "2.7.6" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz#282a3d38863fddcd2e0c220aaed5b90bc156564d" + integrity sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw== + dependencies: + schema-utils "^4.0.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.9: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +optionator@^0.9.1: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-limit@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" + integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== + dependencies: + yocto-queue "^1.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" + integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== + dependencies: + p-limit "^4.0.0" + +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-exists@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" + integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-dir@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-7.0.0.tgz#8f0c08d6df4476756c5ff29b3282d0bab7517d11" + integrity sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA== + dependencies: + find-up "^6.3.0" + +postcss-calc@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-9.0.1.tgz#a744fd592438a93d6de0f1434c572670361eb6c6" + integrity sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ== + dependencies: + postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" + +postcss-colormin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-6.0.0.tgz#d4250652e952e1c0aca70c66942da93d3cdeaafe" + integrity sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw== + dependencies: + browserslist "^4.21.4" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.2.0" + +postcss-convert-values@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz#ec94a954957e5c3f78f0e8f65dfcda95280b8996" + integrity sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw== + dependencies: + browserslist "^4.21.4" + postcss-value-parser "^4.2.0" + +postcss-discard-comments@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz#9ca335e8b68919f301b24ba47dde226a42e535fe" + integrity sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw== + +postcss-discard-duplicates@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz#c26177a6c33070922e67e9a92c0fd23d443d1355" + integrity sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA== + +postcss-discard-empty@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz#06c1c4fce09e22d2a99e667c8550eb8a3a1b9aee" + integrity sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ== + +postcss-discard-overridden@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz#49c5262db14e975e349692d9024442de7cd8e234" + integrity sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw== + +postcss-merge-longhand@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz#6f627b27db939bce316eaa97e22400267e798d69" + integrity sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg== + dependencies: + postcss-value-parser "^4.2.0" + stylehacks "^6.0.0" + +postcss-merge-rules@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz#39f165746404e646c0f5c510222ccde4824a86aa" + integrity sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw== + dependencies: + browserslist "^4.21.4" + caniuse-api "^3.0.0" + cssnano-utils "^4.0.0" + postcss-selector-parser "^6.0.5" + +postcss-minify-font-values@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz#68d4a028f9fa5f61701974724b2cc9445d8e6070" + integrity sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-minify-gradients@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz#22b5c88cc63091dadbad34e31ff958404d51d679" + integrity sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA== + dependencies: + colord "^2.9.1" + cssnano-utils "^4.0.0" + postcss-value-parser "^4.2.0" + +postcss-minify-params@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz#2b3a85a9e3b990d7a16866f430f5fd1d5961b539" + integrity sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ== + dependencies: + browserslist "^4.21.4" + cssnano-utils "^4.0.0" + postcss-value-parser "^4.2.0" + +postcss-minify-selectors@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz#5046c5e8680a586e5a0cad52cc9aa36d6be5bda2" + integrity sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524" + integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-normalize-charset@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz#36cc12457259064969fb96f84df491652a4b0975" + integrity sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ== + +postcss-normalize-display-values@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz#8d2961415078644d8c6bbbdaf9a2fdd60f546cd4" + integrity sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-positions@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz#25b96df99a69f8925f730eaee0be74416865e301" + integrity sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-repeat-style@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz#ddf30ad8762feb5b1eb97f39f251acd7b8353299" + integrity sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-string@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz#948282647a51e409d69dde7910f0ac2ff97cb5d8" + integrity sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-timing-functions@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz#5f13e650b8c43351989fc5de694525cc2539841c" + integrity sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-unicode@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz#741b3310f874616bdcf07764f5503695d3604730" + integrity sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg== + dependencies: + browserslist "^4.21.4" + postcss-value-parser "^4.2.0" + +postcss-normalize-url@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz#d0a31e962a16401fb7deb7754b397a323fb650b4" + integrity sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-whitespace@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz#accb961caa42e25ca4179b60855b79b1f7129d4d" + integrity sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-ordered-values@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz#374704cdff25560d44061d17ba3c6308837a3218" + integrity sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg== + dependencies: + cssnano-utils "^4.0.0" + postcss-value-parser "^4.2.0" + +postcss-reduce-initial@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz#7d16e83e60e27e2fa42f56ec0b426f1da332eca7" + integrity sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA== + dependencies: + browserslist "^4.21.4" + caniuse-api "^3.0.0" + +postcss-reduce-transforms@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz#28ff2601a6d9b96a2f039b3501526e1f4d584a46" + integrity sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: + version "6.0.13" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" + integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-svgo@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-6.0.0.tgz#7b18742d38d4505a0455bbe70d52b49f00eaf69d" + integrity sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw== + dependencies: + postcss-value-parser "^4.2.0" + svgo "^3.0.2" + +postcss-unique-selectors@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz#c94e9b0f7bffb1203894e42294b5a1b3fb34fbe1" + integrity sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.4.21, postcss@^8.4.24: + version "8.4.27" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057" + integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== + dependencies: + lodash "^4.17.20" + renderkid "^3.0.0" + +pretty-format@^29.0.0, pretty-format@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47" + integrity sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg== + dependencies: + "@jest/schemas" "^29.6.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +readable-stream@^2.0.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-runtime@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" + integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== + +regenerator-transform@^0.15.2: + version "0.15.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== + dependencies: + "@babel/regjsgen" "^0.8.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== + +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^6.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0: + version "1.22.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" + integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0, schema-utils@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" + integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" + integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== + dependencies: + node-forge "^1" + +semver@^5.6.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.2.1, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +source-map-js@^1.0.1, source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.3.tgz#bba8daac19930169c0c9c96706749a597ae3acff" + integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw== + +stylehacks@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-6.0.0.tgz#9fdd7c217660dae0f62e14d51c89f6c01b3cb738" + integrity sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw== + dependencies: + browserslist "^4.21.4" + postcss-selector-parser "^6.0.4" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +svgo@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.0.2.tgz#5e99eeea42c68ee0dc46aa16da093838c262fe0a" + integrity sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^5.1.0" + css-tree "^2.2.1" + csso "^5.0.5" + picocolors "^1.0.0" + +table@^6.0.9: + version "6.8.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.7, terser-webpack-plugin@^5.3.9: + version "5.3.9" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" + integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.16.8" + +terser@^5.10.0, terser@^5.16.8: + version "5.19.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.2.tgz#bdb8017a9a4a8de4663a7983f45c506534f9234e" + integrity sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.3: + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url-loader@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" + integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== + dependencies: + loader-utils "^2.0.0" + mime-types "^2.1.27" + schema-utils "^3.0.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" + integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webpack-cli@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" + colorette "^2.0.14" + commander "^10.0.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^5.7.3" + +webpack-dev-middleware@^5.3.1: + version "5.3.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" + integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + dependencies: + colorette "^2.0.10" + memfs "^3.4.3" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@4.13.3: + version "4.13.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.13.3.tgz#9feb740b8b56b886260bae1360286818a221bae8" + integrity sha512-KqqzrzMRSRy5ePz10VhjyL27K2dxqwXQLP5rAKwRJBPUahe7Z2bBWzHw37jeb8GCPKxZRO79ZdQUAPesMh/Nug== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/serve-static" "^1.13.10" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.5.1" + ansi-html-community "^0.0.8" + bonjour-service "^1.0.11" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^2.0.0" + default-gateway "^6.0.3" + express "^4.17.3" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.3" + ipaddr.js "^2.0.1" + launch-editor "^2.6.0" + open "^8.0.9" + p-retry "^4.5.0" + rimraf "^3.0.2" + schema-utils "^4.0.0" + selfsigned "^2.1.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^5.3.1" + ws "^8.13.0" + +webpack-merge@^5.7.3: + version "5.9.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" + integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.88.2: + version "5.88.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" + integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.0" + "@webassemblyjs/ast" "^1.11.5" + "@webassemblyjs/wasm-edit" "^1.11.5" + "@webassemblyjs/wasm-parser" "^1.11.5" + acorn "^8.7.1" + acorn-import-assertions "^1.9.0" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.15.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.7" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +ws@^8.13.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yocto-queue@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" + integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== From f21907046503b24d90a37381cb127a5ef6c82dad Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 10 Aug 2023 14:59:01 -0700 Subject: [PATCH 104/196] Get the tools loaded --- wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts | 2 ++ wasm/tests/clvm-tools-interface/tsconfig.json | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 991911cf7..09a6115f6 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -1,5 +1,6 @@ import MyLibrary from '../index'; import * as bls_loader from 'bls-signatures'; +var clvm_tools_rs = require('../../../../../pkg/clvm_tools_wasm'); it('Runs without crashing', () => { new MyLibrary(); @@ -9,4 +10,5 @@ it('Has BLS signatures support', async () => { let bls = await bls_loader.default(); let g1element = new bls.G1Element(); console.log(g1element.serialize()); + console.log(clvm_tools_rs); }); diff --git a/wasm/tests/clvm-tools-interface/tsconfig.json b/wasm/tests/clvm-tools-interface/tsconfig.json index 639484c09..9ea99e98e 100644 --- a/wasm/tests/clvm-tools-interface/tsconfig.json +++ b/wasm/tests/clvm-tools-interface/tsconfig.json @@ -5,6 +5,7 @@ "module": "esnext", "target": "es5", "allowJs": true, + "checkJs": false, "sourceMap": true, "declaration": true, "emitDeclarationOnly": true, @@ -14,4 +15,4 @@ }, "include": ["src/lib"], "exclude": ["src/lib/**/tests"], -} \ No newline at end of file +} From edea9125ce946c0bd7ef1ad2a9619027156a6ff3 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 11 Aug 2023 10:43:38 -0700 Subject: [PATCH 105/196] Start hooking up the program object --- wasm/Cargo.lock | 1 + wasm/Cargo.toml | 1 + wasm/src/api.rs | 43 +++++++++++++++++++ wasm/src/jsval.rs | 6 +++ .../src/lib/tests/index.test.ts | 13 +++++- 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index c64baa9f3..7fa9d0781 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -153,6 +153,7 @@ dependencies = [ "clvm_tools_rs", "clvmr", "js-sys", + "num-bigint", "wasm-bindgen", "wasm-bindgen-test", ] diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 95c8cc9d2..a293f9ac6 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -22,3 +22,4 @@ clvmr = { version = "0.2.5", features = ["pre-eval"] } wasm-bindgen = "=0.2.83" wasm-bindgen-test = "=0.3.25" js-sys = "0.3.60" +num-bigint = "0.4.0" diff --git a/wasm/src/api.rs b/wasm/src/api.rs index 36f2db93e..68155a90e 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -59,6 +59,9 @@ thread_local! { static REPLS: RefCell> = { return RefCell::new(HashMap::new()); }; + static OBJECTS: RefCell>> = { + return RefCell::new(HashMap::new()); + }; } fn get_next_id() -> i32 { @@ -492,3 +495,43 @@ pub fn sexp_to_string(v: &JsValue) -> JsValue { .map(|s| JsValue::from_str(&s.to_string())) .unwrap_or_else(|| create_clvm_runner_err("unable to convert to value".to_string())) } + +#[wasm_bindgen(inspectable)] +pub struct Program { + internal: i32 +} + +#[wasm_bindgen] +impl Program { + #[wasm_bindgen(static_method_of = Program)] + pub fn to(input: &JsValue) -> Result { + let loc = Srcloc::start(&"*val*".to_string()); + let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| Err(create_clvm_runner_err("unable to convert to value".to_string())))?; + let new_id = get_next_id(); + let result = Program { internal: new_id }; + + OBJECTS.with(|objects| { + objects.replace_with(|objects| { + let mut work_objects = HashMap::new(); + swap(&mut work_objects, objects); + work_objects.insert(new_id, sexp); + work_objects + }) + }); + + Ok(result) + } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> String { + self.to_string_impl() + } + + #[wasm_bindgen(js_name = toString)] + pub fn to_string_impl(&self) -> String { + OBJECTS.with(|objects| { + let objects = objects.borrow(); + objects.get(&self.internal).map(|o| o.to_string()).unwrap_or_else(|| "".to_string()) + }) + } +} diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 3ca5ed42d..8e05fb75b 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -1,6 +1,9 @@ use js_sys; use js_sys::JSON::stringify; use js_sys::{Array, BigInt, Object}; + +use num_bigint::ToBigInt; + use std::borrow::Borrow; use std::collections::HashMap; use std::rc::Rc; @@ -159,6 +162,9 @@ pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { .and_then(|v| v.as_string()) .and_then(|v| v.parse::().ok()) .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) + } else if let Some(fval) = v.as_f64() { + (fval as i64).to_bigint() + .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) } else if Array::is_array(v) { let a = Array::from(v); let mut result_value = Rc::new(SExp::Nil(Srcloc::start(&"*js*".to_string()))); diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 09a6115f6..ba7c952af 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -9,6 +9,15 @@ it('Runs without crashing', () => { it('Has BLS signatures support', async () => { let bls = await bls_loader.default(); let g1element = new bls.G1Element(); - console.log(g1element.serialize()); - console.log(clvm_tools_rs); + console.log(g1element.__proto__); + console.log(bls.G1Element); + console.log(bls.G1Element.SIZE); + console.log(g1element instanceof bls.G1Element); + let g2element = new bls.G2Element(); + console.log(g2element.__proto__); + console.log(bls.G2Element.SIZE); + let converted_g1_element = clvm_tools_rs.sexp_to_string(g1element); + let p = clvm_tools_rs.Program.to(13); + console.log(p.toString()); + console.log(converted_g1_element); }); From ec2ba72e4503646448bb1a87e74ab655afa453a7 Mon Sep 17 00:00:00 2001 From: arty Date: Sun, 13 Aug 2023 21:53:18 -0700 Subject: [PATCH 106/196] Start formalizing --- wasm/src/api.rs | 8 ++--- wasm/src/jsval.rs | 34 ++++++++++++++++++- .../src/lib/tests/index.test.ts | 13 ++----- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/wasm/src/api.rs b/wasm/src/api.rs index 68155a90e..506fbe0da 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -491,6 +491,7 @@ pub fn repl_run_string(repl_id: i32, input: String) -> JsValue { #[wasm_bindgen] pub fn sexp_to_string(v: &JsValue) -> JsValue { let loc = Srcloc::start(&"*val*".to_string()); + sexp_from_js_object(loc, v) .map(|s| JsValue::from_str(&s.to_string())) .unwrap_or_else(|| create_clvm_runner_err("unable to convert to value".to_string())) @@ -506,7 +507,7 @@ impl Program { #[wasm_bindgen(static_method_of = Program)] pub fn to(input: &JsValue) -> Result { let loc = Srcloc::start(&"*val*".to_string()); - let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| Err(create_clvm_runner_err("unable to convert to value".to_string())))?; + let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| Err(create_clvm_runner_err(format!("unable to convert to value"))))?; let new_id = get_next_id(); let result = Program { internal: new_id }; @@ -522,11 +523,6 @@ impl Program { Ok(result) } - #[wasm_bindgen(js_name = toJSON)] - pub fn to_json(&self) -> String { - self.to_string_impl() - } - #[wasm_bindgen(js_name = toString)] pub fn to_string_impl(&self) -> String { OBJECTS.with(|objects| { diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 8e05fb75b..1d146a672 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -1,11 +1,13 @@ use js_sys; use js_sys::JSON::stringify; -use js_sys::{Array, BigInt, Object}; +use js_sys::{Array, BigInt, Object, Reflect}; +use wasm_bindgen::JsCast; use num_bigint::ToBigInt; use std::borrow::Borrow; use std::collections::HashMap; +use std::convert::TryFrom; use std::rc::Rc; use std::str::FromStr; @@ -16,6 +18,8 @@ use clvm_tools_rs::util::Number; use wasm_bindgen::prelude::*; +const G1_ELEMENT_LENGTH: u32 = 48; + pub fn array_to_value(v: Array) -> JsValue { let jref: &JsValue = v.as_ref(); jref.clone() @@ -154,6 +158,32 @@ fn location(o: &Object) -> Option { }) } +pub fn detect_g1(loc: &Srcloc, v: &JsValue) -> Option> { + let serialize_key = JsValue::from_str("serialize"); + js_sys::Reflect::get(v, &serialize_key).ok().and_then(|serialize| { + Reflect::apply(serialize.unchecked_ref(), v, &js_sys::Array::new()).ok().and_then(|array| { + Array::try_from(array).ok().and_then(|array| { + let mut bytes_array: Vec = vec![]; + if array.length() != G1_ELEMENT_LENGTH { + return None; + } + for item in array.iter() { + if let Some(n) = item.as_f64() { + if n < 0.0 || n > 255.0 { + return None; + } + bytes_array.push(n as u8); + } else { + return None; + } + } + + return Some(Rc::new(SExp::QuotedString(loc.clone(), b'x', bytes_array))); + }) + }) + }) +} + pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { if v.is_bigint() { BigInt::new(v) @@ -165,6 +195,8 @@ pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { } else if let Some(fval) = v.as_f64() { (fval as i64).to_bigint() .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) + } else if let Some(g1_bytes) = detect_g1(&sstart, v) { + Some(g1_bytes) } else if Array::is_array(v) { let a = Array::from(v); let mut result_value = Rc::new(SExp::Nil(Srcloc::start(&"*js*".to_string()))); diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index ba7c952af..7776cfc94 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -9,15 +9,6 @@ it('Runs without crashing', () => { it('Has BLS signatures support', async () => { let bls = await bls_loader.default(); let g1element = new bls.G1Element(); - console.log(g1element.__proto__); - console.log(bls.G1Element); - console.log(bls.G1Element.SIZE); - console.log(g1element instanceof bls.G1Element); - let g2element = new bls.G2Element(); - console.log(g2element.__proto__); - console.log(bls.G2Element.SIZE); - let converted_g1_element = clvm_tools_rs.sexp_to_string(g1element); - let p = clvm_tools_rs.Program.to(13); - console.log(p.toString()); - console.log(converted_g1_element); + let converted_g1_element = clvm_tools_rs.Program.to(g1element); + console.log(converted_g1_element.toString()); }); From 31ad2a60d9420c944f831f2885fe8d6ce8322168 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 17 Aug 2023 14:17:30 -0700 Subject: [PATCH 107/196] Add exhaustive test run and game referee tests from bram's code, now that all one branch can contain all needed features --- .github/workflows/extensive-tests.yml | 127 +++++ .gitignore | 7 +- .../game-referee-after-cl21/handcalc.clinc | 140 +++++ .../game-referee-after-cl21/handcalc_a.clinc | 256 ++++++++++ .../smoke_test_deep_compare.clsp | 28 + .../smoke_test_permutations.clsp | 9 + .../smoke_test_sort.clsp | 11 + .../spacehandcalc.clinc | 104 ++++ .../test_handcalc.clsp | 379 ++++++++++++++ .../test_handcalc_b.clsp | 377 ++++++++++++++ .../test_library_basics.py | 165 ++++++ .../test_permutations.clsp | 63 +++ .../game-referee-after-cl21/test_prepend.clsp | 5 + .../game-referee-after-cl21/test_range.clsp | 6 + .../game-referee-after-cl21/test_reverse.clsp | 6 + .../game-referee-after-cl21/test_sort.clsp | 37 ++ .../game-referee-after-cl21/testnoncegame.py | 33 ++ .../game-referee-after-cl21/testreferee.py | 479 ++++++++++++++++++ .../testrockpaperscissors.py | 48 ++ .../tests/game-referee-in-cl21/handcalc.clinc | 140 +++++ .../game-referee-in-cl21/handcalc_a.clinc | 256 ++++++++++ .../smoke_test_deep_compare.clsp | 28 + .../smoke_test_deep_compare.clvm.hex | 1 + .../smoke_test_deep_compare.sym | 1 + .../smoke_test_permutations.clsp | 9 + .../smoke_test_permutations.clvm.hex | 1 + .../smoke_test_permutations.sym | 1 + .../game-referee-in-cl21/smoke_test_sort.clsp | 11 + .../smoke_test_sort.clvm.hex | 1 + .../game-referee-in-cl21/smoke_test_sort.sym | 1 + .../game-referee-in-cl21/spacehandcalc.clinc | 104 ++++ .../game-referee-in-cl21/test_handcalc.clsp | 379 ++++++++++++++ .../test_handcalc.clvm.hex | 1 + .../game-referee-in-cl21/test_handcalc.sym | 1 + .../game-referee-in-cl21/test_handcalc_b.clsp | 377 ++++++++++++++ .../test_library_basics.py | 165 ++++++ .../test_permutations.clsp | 63 +++ .../test_permutations.clvm.hex | 1 + .../test_permutations.sym | 1 + .../game-referee-in-cl21/test_prepend.clsp | 5 + .../test_prepend.clvm.hex | 1 + .../game-referee-in-cl21/test_prepend.sym | 1 + .../game-referee-in-cl21/test_range.clsp | 6 + .../game-referee-in-cl21/test_range.clvm.hex | 1 + .../tests/game-referee-in-cl21/test_range.sym | 1 + .../game-referee-in-cl21/test_reverse.clsp | 6 + .../test_reverse.clvm.hex | 1 + .../game-referee-in-cl21/test_reverse.sym | 1 + .../tests/game-referee-in-cl21/test_sort.clsp | 37 ++ .../game-referee-in-cl21/test_sort.clvm.hex | 1 + .../tests/game-referee-in-cl21/test_sort.sym | 1 + .../game-referee-in-cl21/testnoncegame.py | 33 ++ .../tests/game-referee-in-cl21/testreferee.py | 479 ++++++++++++++++++ .../testrockpaperscissors.py | 48 ++ resources/tests/lib/__init__.py | 0 resources/tests/lib/all-in-list.clinc | 12 + resources/tests/lib/assert.clinc | 8 + resources/tests/lib/busy.clinc | 11 + resources/tests/lib/condition_codes.clinc | 41 ++ resources/tests/lib/curry-and-treehash.clinc | 92 ++++ resources/tests/lib/curry.clinc | 104 ++++ resources/tests/lib/deep_compare.clinc | 41 ++ resources/tests/lib/filtermap.clinc | 14 + resources/tests/lib/flatten.clinc | 12 + resources/tests/lib/last.clinc | 39 ++ resources/tests/lib/len.clinc | 3 + resources/tests/lib/load_clvm.py | 168 ++++++ resources/tests/lib/map.clinc | 17 + resources/tests/lib/match.clinc | 12 + resources/tests/lib/max.clinc | 13 + resources/tests/lib/permutations.clinc | 21 + resources/tests/lib/prefix.clinc | 16 + resources/tests/lib/prepend.clinc | 8 + resources/tests/lib/print.clinc | 3 + resources/tests/lib/program.py | 231 +++++++++ resources/tests/lib/range.clinc | 11 + resources/tests/lib/reduce.clinc | 10 + resources/tests/lib/reverse.clinc | 11 + resources/tests/lib/shatree.clinc | 11 + resources/tests/lib/slice.clinc | 10 + .../tests/lib/smoke_test_deep_compare.clsp | 28 + .../tests/lib/smoke_test_permutations.clsp | 9 + resources/tests/lib/smoke_test_sort.clsp | 11 + resources/tests/lib/sort.clinc | 44 ++ resources/tests/lib/steprun.py | 69 +++ resources/tests/lib/tree_hash.py | 62 +++ resources/tests/lib/utils.clinc | 17 + support/test-game-referee.sh | 16 + 88 files changed, 5618 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/extensive-tests.yml create mode 100644 resources/tests/game-referee-after-cl21/handcalc.clinc create mode 100644 resources/tests/game-referee-after-cl21/handcalc_a.clinc create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_sort.clsp create mode 100644 resources/tests/game-referee-after-cl21/spacehandcalc.clinc create mode 100644 resources/tests/game-referee-after-cl21/test_handcalc.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_handcalc_b.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_library_basics.py create mode 100644 resources/tests/game-referee-after-cl21/test_permutations.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_prepend.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_range.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_reverse.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_sort.clsp create mode 100644 resources/tests/game-referee-after-cl21/testnoncegame.py create mode 100644 resources/tests/game-referee-after-cl21/testreferee.py create mode 100644 resources/tests/game-referee-after-cl21/testrockpaperscissors.py create mode 100644 resources/tests/game-referee-in-cl21/handcalc.clinc create mode 100644 resources/tests/game-referee-in-cl21/handcalc_a.clinc create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_deep_compare.sym create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_permutations.sym create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_sort.clsp create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_sort.sym create mode 100644 resources/tests/game-referee-in-cl21/spacehandcalc.clinc create mode 100644 resources/tests/game-referee-in-cl21/test_handcalc.clsp create mode 100644 resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_handcalc.sym create mode 100644 resources/tests/game-referee-in-cl21/test_handcalc_b.clsp create mode 100644 resources/tests/game-referee-in-cl21/test_library_basics.py create mode 100644 resources/tests/game-referee-in-cl21/test_permutations.clsp create mode 100644 resources/tests/game-referee-in-cl21/test_permutations.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_permutations.sym create mode 100644 resources/tests/game-referee-in-cl21/test_prepend.clsp create mode 100644 resources/tests/game-referee-in-cl21/test_prepend.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_prepend.sym create mode 100644 resources/tests/game-referee-in-cl21/test_range.clsp create mode 100644 resources/tests/game-referee-in-cl21/test_range.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_range.sym create mode 100644 resources/tests/game-referee-in-cl21/test_reverse.clsp create mode 100644 resources/tests/game-referee-in-cl21/test_reverse.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_reverse.sym create mode 100644 resources/tests/game-referee-in-cl21/test_sort.clsp create mode 100644 resources/tests/game-referee-in-cl21/test_sort.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_sort.sym create mode 100644 resources/tests/game-referee-in-cl21/testnoncegame.py create mode 100644 resources/tests/game-referee-in-cl21/testreferee.py create mode 100644 resources/tests/game-referee-in-cl21/testrockpaperscissors.py create mode 100644 resources/tests/lib/__init__.py create mode 100644 resources/tests/lib/all-in-list.clinc create mode 100644 resources/tests/lib/assert.clinc create mode 100644 resources/tests/lib/busy.clinc create mode 100644 resources/tests/lib/condition_codes.clinc create mode 100644 resources/tests/lib/curry-and-treehash.clinc create mode 100644 resources/tests/lib/curry.clinc create mode 100644 resources/tests/lib/deep_compare.clinc create mode 100644 resources/tests/lib/filtermap.clinc create mode 100644 resources/tests/lib/flatten.clinc create mode 100644 resources/tests/lib/last.clinc create mode 100644 resources/tests/lib/len.clinc create mode 100644 resources/tests/lib/load_clvm.py create mode 100644 resources/tests/lib/map.clinc create mode 100644 resources/tests/lib/match.clinc create mode 100644 resources/tests/lib/max.clinc create mode 100644 resources/tests/lib/permutations.clinc create mode 100644 resources/tests/lib/prefix.clinc create mode 100644 resources/tests/lib/prepend.clinc create mode 100644 resources/tests/lib/print.clinc create mode 100644 resources/tests/lib/program.py create mode 100644 resources/tests/lib/range.clinc create mode 100644 resources/tests/lib/reduce.clinc create mode 100644 resources/tests/lib/reverse.clinc create mode 100644 resources/tests/lib/shatree.clinc create mode 100644 resources/tests/lib/slice.clinc create mode 100644 resources/tests/lib/smoke_test_deep_compare.clsp create mode 100644 resources/tests/lib/smoke_test_permutations.clsp create mode 100644 resources/tests/lib/smoke_test_sort.clsp create mode 100644 resources/tests/lib/sort.clinc create mode 100644 resources/tests/lib/steprun.py create mode 100644 resources/tests/lib/tree_hash.py create mode 100644 resources/tests/lib/utils.clinc create mode 100755 support/test-game-referee.sh diff --git a/.github/workflows/extensive-tests.yml b/.github/workflows/extensive-tests.yml new file mode 100644 index 000000000..b4be9eab8 --- /dev/null +++ b/.github/workflows/extensive-tests.yml @@ -0,0 +1,127 @@ +# Taken from clvm_rs' version. +name: Extensive tests + +on: + push: + branches: + - main + - dev + tags: + - '**' + pull_request: + branches: + - '**' + +jobs: + extensive_tests: + name: Extensive tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up rusts + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: rustfmt, clippy + + - name: Set up rust (stable) + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: rustfmt, clippy + + - uses: actions/setup-python@v4 + name: Install Python 3.11 + with: + python-version: 3.11 + + - name: Update pip + run: | + python -m pip install --upgrade pip + + - name: Set up rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + + - name: Install dependencies + run: | + python -m pip install maturin==1.1.0 + + - name: Build Linux in manylinux2010 with maturin on Python ${{ matrix.python }} + run: | + podman run --rm=true \ + -v ${{ github.workspace }}:/ws:rw --workdir=/ws \ + ghcr.io/chia-network/build-images/centos-pypa-rust-x86_64 \ + bash -exc '\ + yum -y install libc6 openssl-devel && \ + source $HOME/.cargo/env && \ + rustup target add x86_64-unknown-linux-musl && \ + rm -rf venv && \ + PY_VERSION=${{ matrix.python }} + PY_VERSION=${PY_VERSION/.} && \ + echo "Python version with dot removed is $PY_VERSION" && \ + if [ "$PY_VERSION" = "37" ]; \ + then export SCND_VERSION="${PY_VERSION}m"; \ + else export SCND_VERSION="$PY_VERSION"; fi && \ + echo "Exporting path /opt/python/cp$PY_VERSION-cp$SCND_VERSION/bin" && \ + export PATH=/opt/python/cp$PY_VERSION-cp$SCND_VERSION/bin/:$PATH && \ + /opt/python/cp38-cp38/bin/python -m venv venv && \ + if [ ! -f "activate" ]; then ln -s venv/bin/activate; fi && \ + . ./activate && \ + pip install --upgrade pip + ' + docker run --rm -v $(pwd):/io ghcr.io/pyo3/maturin:v1.1.0 build --release --strip --manylinux 2014 + # Refresh in case any ownerships changed. + mv target target.docker && cp -r target.docker target + # Ensure an empty .cargo-lock file exists. + touch target/release/.cargo-lock + + - name: Set up feature flags to use + shell: bash + run: | + python -m pip install tomlkit + USE_FEATURES=$(./support/feature-fishing.py) + echo "USE_FEATURES=${USE_FEATURES}" >> "$GITHUB_ENV" + + - name: Install clvm_tools_rs wheel + if: ${{ !startsWith(matrix.os, 'windows') }} + run: | + . ./activate + ls target/wheels/ + # this mess puts the name of the `.whl` file into `$WHEEL_PATH` + # remove the dot, use the `glob` lib to grab the file from the directory + export WHEEL_PATH=$(echo ${{ matrix.python }} | python -c 'DOTLESS=input().replace(".", ""); import glob; print(" ".join(filter(lambda x: "musl" not in x, glob.glob("target/wheels/clvm_tools_rs-*-cp*-*.whl"))))' ) + echo ${WHEEL_PATH} + pip install ${WHEEL_PATH} + + - name: Install other wheels + run: | + . ./activate + python -m pip install pytest + python -m pip install blspy + + - name: install clvm & clvm_tools + run: | + . ./activate + git clone https://github.com/Chia-Network/clvm.git --branch=main --single-branch + python -m pip install ./clvm + + echo "installing clvm_rs via pip" + pip install clvm_rs + + echo "installing clvm_tools for clvm tests" + # clvm tools is required to run the tests is clvm + python -m pip install clvm_tools + + - name: Run game referee test + run: | + . ./activate + cp support/test-game-referee.sh . + sh test-game-referee.sh resources/tests/game-referee-in-cl21 diff --git a/.gitignore b/.gitignore index 77e2b42a7..a343936cb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,9 @@ wasm/tests/node_modules resources/tests/bridgeref/*.sym resources/tests/bridgeref/*.clvm.hex resources/tests/gameref21/*.sym -resources/tests/gameref21/*.clvm.hex \ No newline at end of file +resources/tests/gameref21/*.clvm.hex +resources/tests/gameref21/*.clvm.hex +resources/tests/game-referee/*.sym +resources/tests/game-referee/*.clvm.hex +__pycache__ +.pytest_cache diff --git a/resources/tests/game-referee-after-cl21/handcalc.clinc b/resources/tests/game-referee-after-cl21/handcalc.clinc new file mode 100644 index 000000000..6317733f4 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/handcalc.clinc @@ -0,0 +1,140 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun find_flush_inner (suits last count) + (if (not suits) + 0 + (if (= (f suits) last) + (if (= count 4) + last + (find_flush_inner (r suits) last (+ count 1)) + ) + (find_flush_inner (r suits) (f suits) 1) + ) + ) + ) + ; returns the flush suit or 0 if there isn't any + ; suits must be clustered/sorted + (defun find_flush (suits) + (find_flush_inner (sort (lambda (x y) (deep> x y)) suits) 0 0) + ) + (defun straight_high_inner (ranks started_ace last count) + (if (not ranks) + ; at the end of the list + (if (logand (= last 2) (= count 4) started_ace) + ; ace to five + 5 + ; no straight + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner ranks (= (f ranks) 14) 0 0) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (c count last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (c (c count last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush (map rest cards)) + max_flush (if (not fsuit) + 0 + (assign-lambda + fnosuits + (sort + (lambda (x y) (deep> x y)) + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + ) + + fsh (straight_high fnosuits) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice fnosuits 5)) + ) + ) + ) + nosuits (sort (lambda (x y) (deep> x y)) (map first cards)) + sh (straight_high nosuits) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort (lambda (x y) (deep> x y)) (group_by_count nosuits)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + (max (lambda (x y) (deep< x y)) (list max_flush max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/handcalc_a.clinc b/resources/tests/game-referee-after-cl21/handcalc_a.clinc new file mode 100644 index 000000000..06c326392 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/handcalc_a.clinc @@ -0,0 +1,256 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun hand_compare (a b) + (if (= (f a) (f b)) + (if (r a) + (hand_compare (r a) (r b)) + 0 + ) + (- (* 2 (> (f a) (f b))) 1) + ) + ) + (defun hand< (a b) + (= (hand_compare a b) -1) + ) + (defun merge (a b) + (if (not a) + b + (if (not b) + a + (if (> (f a) (f b)) + (c (f a) (merge (r a) b)) + (c (f b) (merge a (r b))) + ) + ) + ) + ) + ; Sorts atoms into descending order + ; This is optimized for sorting short lists + ; A more general function would return a list of lists of ascending sizes + ; to be merged + (defun atomsort ((@ firstpos (first @ secondpos (second @ thirdpos (third . remaining))))) + (if firstpos + (if secondpos + (if thirdpos + (assign-lambda + mylist + (if (> first second) + (if (> second third) + (list first second third) + (if (> first third) + (list first third second) + (list third first second) + ) + ) + (if (> first third) + (list second first third) + (if (> second third) + (list second third first) + (list third second first) + ) + ) + ) + (merge mylist (atomsort remaining)) + ) + (if (> first second) + firstpos + (list second first) + ) + ) + firstpos + ) + 0 + ) + ) + (defun count_suits_2 ((@ suits (firstsuit . remaining))) + (if (not suits) + (c (c 0 0) (c 0 0)) + (assign-lambda ((@ cd (clubs . diamonds)) . (@ hs (hearts . spades))) (count_suits remaining) + (if (= firstsuit 1) + (c (c (+ clubs 1) diamonds) hs) + (if (= firstsuit 2) + (c (c clubs (+ diamonds 1)) hs) + (if (= firstsuit 3) + (c cd (c (+ hearts 1) spades)) + (c cd (c hearts (+ spades 1))) + ) + ) + ) + ) + ) + ) + (defun find_flush_2 (suits) + (assign-lambda ((clubs . diamonds) . (hearts . spades)) (count_suits suits) + (if (> clubs 4) + 1 + (if (> diamonds 4) + 2 + (if (> hearts 4) + 3 + (if (> spades 4) + 4 + 0 + ) + ) + ) + ) + ) + ) + (defun count_suits (suits) + (if suits + (+ (count_suits (r suits)) (ash 1 (* 4 (- (f suits) 1)))) + 0 + ) + ) + (defun find_flush (suits) + (assign-lambda + myvals (count_suits suits) + (if (> (logand myvals 0xF000) 0x4000) + 4 + (if (> (logand myvals 0x0F00) 0x0400) + 3 + (if (> (logand myvals 0x00F0) 0x0040) + 2 + (if (> (logand myvals 0x0F) 0x04) + 1 + 0 + ) + ) + ) + ) + ) + ) + (defun straight_high_inner (ranks last count) + (if (not ranks) + (if (logand (= last 2) (= count 4)) + ; maybe ace to five + 5 + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (assign-lambda high (straight_high_inner ranks 0 0) + (if (= high 5) + (* (= (f ranks) 14) 5) + high + ) + ) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (logior (lsh count 4) last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign-inline val (group_by_count_inner (r items) (f items) 1) + (c (logior (lsh count 4) last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush (map rest cards)) + max_flush (if (not fsuit) + (list 0) + (assign-lambda + flushcards + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + flushranks (atomsort flushcards) + fsh (straight_high flushranks) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice flushranks 5)) + ) + ) + ) + ranks (atomsort (map first cards)) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + (list 0) + ) + groups (map + (lambda (myval) (c (lsh myval -4) (logand myval 0x0F))) + (atomsort (group_by_count ranks)) + ) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + ; max of max_flush max_straight and max_group + (if (> (f max_flush) (f max_straight)) + (if (> (f max_flush) (f max_group)) + max_flush + max_group + ) + (if (> (f max_straight) (f max_group)) + max_straight + max_group + ) + ) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp new file mode 100644 index 000000000..8df629518 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp @@ -0,0 +1,28 @@ +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include deep_compare.clinc) + + (map + (lambda ((want_cmp_val cmp_a cmp_b)) + (= (deep_compare cmp_a cmp_b) want_cmp_val) + ) + (q + (0 0 0) + (-1 () (1 14 5 4 3 2)) + (1 (1 14 5 4 3 2) ()) + (-1 "X" (1 2)) + (1 (1 2) "X") + (0 (3 2) (3 2)) + (-1 (3 1) (3 3)) + (1 (3 3) (3 1)) + (-1 (1 1) (2 1)) + (1 (3 1) (2 2)) + (-1 (2 2) (3 1)) + ) + ) + ) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp b/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp new file mode 100644 index 000000000..2ed3fbbcc --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp @@ -0,0 +1,9 @@ +(mod (X) + (include *standard-cl-21*) + (include map.clinc) + (include prepend.clinc) + (include print.clinc) + (include permutations.clinc) + + (permutations X) + ) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp b/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp new file mode 100644 index 000000000..59b8a886e --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp @@ -0,0 +1,11 @@ +(mod (X) + (include *standard-cl-21*) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include reverse.clinc) + (include print.clinc) + + (sort (lambda (a b) (> b a)) X) + ) diff --git a/resources/tests/game-referee-after-cl21/spacehandcalc.clinc b/resources/tests/game-referee-after-cl21/spacehandcalc.clinc new file mode 100644 index 000000000..3bfae65ca --- /dev/null +++ b/resources/tests/game-referee-after-cl21/spacehandcalc.clinc @@ -0,0 +1,104 @@ + +; ranks are 1-13 with 1 being two, 12 being king, and 13 being ace +; there are no suits, flushes, or ace-to-four straights +; takes a list of card ranks and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; all sorting is done highest to lowest +( + (include *standard-cl-22*) + (include sort.clinc) + (include deep_compare.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include max.clinc) + (defconstant FIVE_OF_A_KIND 10) + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun straight_high_inner (ranks last count) + (if (not ranks) + ; at the end of the list + 0 + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner (ranks (= (f ranks) 13) 0 0)) + ) + (defun group_by_count_inner (items last count) + (if (not items) + 0 + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (if last + (c (c count last) val) + val + ) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items 0 0) + ) + (defun space_hand_calc (cards) + (assign + rest (lambda (x) (r x)) + greater (lambda (x y) (> x y)) + ranks (sort greater cards) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort deep> (group_by_count ranks)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (if (= top_count 4) + (c FOUR_OF_A_KIND (slice topcards 2)) + (c FIVE_OF_A_KIND (slice topcards 1)) + ) + ) + ) + ) + (max deep< (list max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_handcalc.clsp b/resources/tests/game-referee-after-cl21/test_handcalc.clsp new file mode 100644 index 000000000..16c46f664 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_handcalc.clsp @@ -0,0 +1,379 @@ + +(mod () + (include *standard-cl-21*) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include sort.clinc) + (include max.clinc) + (include handcalc.clinc) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + firstval (handcalc firstarg) + secondval (handcalc secondarg) + (assert + (a myfunc (list firstval secondval)) + (deep= firstval (handcalc (reverse firstarg))) + (deep= secondval (handcalc (reverse secondarg))) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp b/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp new file mode 100644 index 000000000..674bbd414 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp @@ -0,0 +1,377 @@ + +(mod () + (include *standard-cl-21*) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include handcalc.clinc) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + firstval (handcalc firstarg) + secondval (handcalc secondarg) + (assert + (a myfunc (list firstval secondval)) + (deep= firstval (handcalc (reverse firstarg))) + (deep= secondval (handcalc (reverse secondarg))) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_library_basics.py b/resources/tests/game-referee-after-cl21/test_library_basics.py new file mode 100644 index 000000000..926ddde7a --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_library_basics.py @@ -0,0 +1,165 @@ +import os +import pytest +import random +from itertools import permutations +from typing import List +#from hsms.streamables.program import Program +#from steprun import diag_run_clvm, compile_module_with_symbols +#from lib.program import Program +from pathlib import Path +from clvm_rs import Program +from lib.steprun import diag_run_clvm, compile_module_with_symbols +from clvm_tools_rs import get_version + +print(f"clvm_tools_rs version is {get_version()}") +#include_dirs = os.getcwd() +include_dirs = [Path(__file__).parent, Path(__file__).parent.parent / "lib"] +Program.set_run_unsafe_max_cost(11000000000) + +print(f"XXX: {include_dirs}") +compile_module_with_symbols(include_dirs, 'smoke_test_deep_compare.clsp') +compare_program = Program.from_bytes(bytes.fromhex(open('smoke_test_deep_compare.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'smoke_test_sort.clsp') +sort_program = Program.from_bytes(bytes.fromhex(open('smoke_test_sort.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_sort.clsp') +test_sort_program = Program.from_bytes(bytes.fromhex(open('test_sort.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_permutations.clsp') +test_permutations_program = Program.from_bytes(bytes.fromhex(open('test_permutations.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_reverse.clsp') +test_reverse_program = Program.from_bytes(bytes.fromhex(open('test_reverse.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_prepend.clsp') +test_prepend_program = Program.from_bytes(bytes.fromhex(open('test_prepend.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_range.clsp') +test_range_program = Program.from_bytes(bytes.fromhex(open('test_range.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'smoke_test_permutations.clsp') +smoke_test_permutations_program = Program.from_bytes(bytes.fromhex(open('smoke_test_permutations.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_handcalc.clsp') +test_handcalc_program = Program.from_bytes(bytes.fromhex(open('test_handcalc.clvm.hex').read())) + +def as_atom_list(prg: Program) -> List[bytes]: + """ + Pretend `prg` is a list of atoms. Return the corresponding + python list of atoms. + + At each step, we always assume a node to be an atom or a pair. + If the assumption is wrong, we exit early. This way we never fail + and always return SOMETHING. + """ + items = [] + obj = prg + while True: + pair = obj.pair + if pair is None: + break + atom = pair[0].atom + if atom is None: + break + items.append(atom) + obj = pair[1] + return items + +def test_smoke_compare(): + compare_program.run(Program.to([])) + +def test_handcalc(): + diag_run_clvm(test_handcalc_program, Program.to([]), 'test_handcalc.sym') + +def proper_list_inner(result,cl): + if hasattr(cl, 'pair') and cl.pair is not None: + result.append(cl.pair[0]) + return proper_list_inner(result,cl.pair[1]) + else: + return result + +def proper_list(cl): + result = [] + return proper_list_inner(result,cl) + +def int_list(cl): + return [Program.to(x).as_int() for x in as_atom_list(Program.to(cl))] + +def de_none_list(l): + return [x if x is not None else [] for x in l] + +def with_random_lists(n,f): + for length in range(n): # 0-10 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + f(orig_list) + +def test_prepend(): + for length1 in range(5): + list_1 = list(range(length1)) + for length2 in range(length1): + prepend_result = test_prepend_program.run([Program.to(list_1[:length2]),Program.to(list_1[length2:])]) + assert list_1 == int_list(prepend_result) + +def test_reverse(): + def test_reverse_list(l): + rev_args = Program.to([l]) + reversed_result = Program.to(list(reversed(l))) + reversed_by_prog = test_reverse_program.run(rev_args) + assert reversed_result == reversed_by_prog + + with_random_lists(10,test_reverse_list) + +def test_range(): + for length in range(10): + want_list = list(range(length)) + result = test_range_program.run(Program.to([length])) + assert want_list == result + +def do_test_permutations_of_size_n(n): + try_list = [random.randint(0,100) for x in range(n)] + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = smoke_test_permutations_program.run(Program.to([try_list])) + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_permutations_0(): + do_test_permutations_of_size_n(0) + +def test_permutations_1(): + do_test_permutations_of_size_n(1) + +def test_permutations_2(): + n = 2 + all_a_string = 0x616161616161 + all_b_string = 0x626262626262 + for try_list in [[all_a_string,all_b_string], [all_b_string,all_a_string]]: + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = diag_run_clvm(smoke_test_permutations_program, Program.to([try_list]), 'smoke_test_permutations.sym') + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_chialisp_sort_program(): + diag_run_clvm(test_sort_program, Program.to([]), 'test_sort.sym') + +def test_permutations_n(): + for i in range(3,6): + do_test_permutations_of_size_n(i) + +def test_chialisp_permutations_program(): + diag_run_clvm(test_permutations_program, Program.to([3, 5]), 'test_permutations.sym') + +def test_smoke_sort(): + for length in range(7): # 0-7 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + sort_args = Program.to([orig_list]) + sorted_list = Program.to(sorted(orig_list)) + sort_res = sort_program.run(sort_args) + assert sort_res == sorted_list + +if __name__ == '__main__': + test_smoke_sort() diff --git a/resources/tests/game-referee-after-cl21/test_permutations.clsp b/resources/tests/game-referee-after-cl21/test_permutations.clsp new file mode 100644 index 000000000..d5b6d125f --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_permutations.clsp @@ -0,0 +1,63 @@ +(mod (M N) + (include *standard-cl-21*) + (include prepend.clinc) + (include reverse.clinc) + (include map.clinc) + (include len.clinc) + (include range.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + (include all-in-list.clinc) + (include print.clinc) + + (defun ! (x) + (if x + (* x (! (- x 1))) + 1 + ) + ) + (defun no_repeats_inner ((first . remainder)) + (if remainder + (if (deep= first (f remainder)) + 0 + (no_repeats_inner remainder) + ) + 1 + ) + ) + (defun no_repeats (mylist) + (if mylist + (no_repeats_inner (sort (lambda (a b) (= (deep_compare a b) -1)) mylist)) + 1 + ) + ) + (assert + ;; Is permutations expected to collapse equal alternatives when two of + ;; the items to shuffle are equal? + (= (* (! M) 4) (len (permutations (c 0 (range M))))) + (busy + (lambda (listlen) + (assign + mylist (range listlen) + permed (permutations mylist) + (assert + (= (len permed) (! listlen)) + ;; ensure we didn't produce any permutations that have + ;; repeated elements in them, which would indicate that + ;; the permutation function misbehaved + (all-in-list (map (lambda (L) (no_repeats L)) permed)) + (no_repeats permed) + ) + ) + ) + (reverse (range N)) + 1 + ) + (deep= (permutations 0) (q ())) + 0 + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_prepend.clsp b/resources/tests/game-referee-after-cl21/test_prepend.clsp new file mode 100644 index 000000000..9f0d45819 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_prepend.clsp @@ -0,0 +1,5 @@ +(mod (X Y) + (include *standard-cl-21*) + (include prepend.clinc) + (prepend X Y) + ) diff --git a/resources/tests/game-referee-after-cl21/test_range.clsp b/resources/tests/game-referee-after-cl21/test_range.clsp new file mode 100644 index 000000000..a7dc5edd9 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_range.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-21*) + (include range.clinc) + + (range X) + ) diff --git a/resources/tests/game-referee-after-cl21/test_reverse.clsp b/resources/tests/game-referee-after-cl21/test_reverse.clsp new file mode 100644 index 000000000..b1d843648 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_reverse.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-21*) + (include reverse.clinc) + + (reverse X) + ) diff --git a/resources/tests/game-referee-after-cl21/test_sort.clsp b/resources/tests/game-referee-after-cl21/test_sort.clsp new file mode 100644 index 000000000..8185024d0 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_sort.clsp @@ -0,0 +1,37 @@ + +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include range.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + + (defun try_list (mylist newlist) + (assert (deep= (print "sorted" (sort (lambda (A B) (deep< A B)) newlist)) mylist) 0) + ) + + (defun try_permuted_list (mylist) + (busy (lambda ((& mylist) newlist) (try_list mylist newlist)) + (print "sort all these" (permutations (print "mylist" mylist))) + 0 + ) + ) + (last + (try_list 0 0) + (try_list (range 15) (range 15)) + (try_list (range 15) (reverse (range 15))) + (try_permuted_list (list -1 -1 0 0 2)) + (busy (lambda (i) (try_permuted_list (print "sortme" (range i)))) + (range 4) + 0 + ) + 1 + ) +) diff --git a/resources/tests/game-referee-after-cl21/testnoncegame.py b/resources/tests/game-referee-after-cl21/testnoncegame.py new file mode 100644 index 000000000..3b4cd2c2a --- /dev/null +++ b/resources/tests/game-referee-after-cl21/testnoncegame.py @@ -0,0 +1,33 @@ +import hashlib + +from hsms.streamables.program import Program + +from clvm.EvalError import EvalError + +noncegame = Program.from_bytes(bytes.fromhex(open("noncegame.clvm.hex").read())) +noncehash = noncegame.tree_hash() + +def drun(prog: Program, args: Program): + try: + return prog.run(args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(args)}") + raise + +def testnonce(startnonce, maxnonce): + for i in range(startnonce, maxnonce): + mygame = noncegame.curry(i, noncehash) + good_parameters = [i*2, noncegame.curry(i+1, noncehash).tree_hash(), 1, (i*4, b'g')] + bad_parameters = [i*3, noncegame.curry(i+2, noncehash).tree_hash(), 2, (i*5, b'g')] + assert drun(mygame, good_parameters) == b'g' + for j in range(len(good_parameters)): + try: + p = list(good_parameters) + p[j] = bad_parameters[j] + mygame.run(p) + assert False + except EvalError as ee: + pass + +if __name__ == '__main__': + testnonce(3, 7) diff --git a/resources/tests/game-referee-after-cl21/testreferee.py b/resources/tests/game-referee-after-cl21/testreferee.py new file mode 100644 index 000000000..01eb53643 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/testreferee.py @@ -0,0 +1,479 @@ +import pytest +from hashlib import sha256 +from contextlib import asynccontextmanager +from chia.clvm.spend_sim import SimClient, SpendSim +from pathlib import Path +from clvm.casts import int_to_bytes, int_from_bytes + +from hsms.streamables.program import Program +from clvm_tools_rs import compile_clvm +from clvm_tools.binutils import disassemble + +from clvm.EvalError import EvalError +from chia.types.mempool_inclusion_status import MempoolInclusionStatus +from chia.util.errors import Err +from dataclasses import dataclass +from typing import Any +from chia_rs import Coin +from chia.types.spend_bundle import SpendBundle +from chia.types.coin_spend import CoinSpend +from blspy import G2Element + +from steprun import diag_run_clvm, compile_module_with_symbols + +compile_module_with_symbols(['.'],'referee.clsp') +referee = Program.from_bytes(bytes.fromhex(open("referee.clvm.hex").read())) +refhash = referee.tree_hash() +compile_module_with_symbols(['.'],'referee_accuse.clsp') +referee_accuse = Program.from_bytes(bytes.fromhex(open("referee_accuse.clvm.hex").read())) +refaccusehash = referee.tree_hash() +compile_clvm('rockpaperscissorsa.clsp', 'rockpaperscissorsa.clvm.hex', ['.']) +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +compile_clvm('rockpaperscissorsb.clsp', 'rockpaperscissorsb.clvm.hex', ['.']) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +compile_clvm('rockpaperscissorsc.clsp', 'rockpaperscissorsc.clvm.hex', ['.']) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +compile_clvm('rockpaperscissorsd.clsp', 'rockpaperscissorsd.clvm.hex', ['.']) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + +move = 0 +accuse = 1 +timeout = 2 + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha(blob:bytes) -> bytes: + return sha256(blob).digest() + +@pytest.fixture(scope="function") +@asynccontextmanager +async def setup_sim() : + sim = await SpendSim.create(db_path=Path("file:db_test?mode=memory&cache=shared")) + sim_client = SimClient(sim) + await sim.farm_block() + + try: + yield sim, sim_client + finally: + await sim.close() + +def bootstrap_referee(parent_coin_id, initial_validation_program_hash, initial_split, + amount, timeout, max_move_size, mover_puzzle, waiter_puzzle): + """ + returns referee_wrap + """ + puzzle_hash = referee.curry( + [initial_validation_program_hash, 0, initial_split, amount, timeout, max_move_size, mover_puzzle.tree_hash(), + waiter_puzzle.tree_hash(), referee.tree_hash()]).tree_hash() + coin = Coin(parent_coin_id, puzzle_hash, amount) + return RefereeWrap(coin, bytes(32), bytes(32), bytes(32), + initial_validation_program_hash, 0, initial_split, timeout, max_move_size, + mover_puzzle, waiter_puzzle) + +@dataclass +class RefereeWrap: + coin: Any + grandparent_id: Any + parent_validation_program_hash: Any + parent_everything_else_hash: Any + validation_program_hash: Any + move: Any + split: Any + timeout: Any + max_move_size: Any + mover_puzzle: Any + waiter_puzzle: Any + + def curried_parameters_for_our_puzzle(self, purpose, for_self, move_to_make, split, validation_program_hash): + result = Program.to([ + validation_program_hash, + move_to_make, + split, + self.coin.amount, + self.timeout, + self.max_move_size, + self.mover_puzzle.tree_hash() if for_self else self.waiter_puzzle.tree_hash(), + self.waiter_puzzle.tree_hash() if for_self else self.mover_puzzle.tree_hash(), + refhash + ]) + print(f'for {purpose} curried_parameters_for_our_puzzle is {result}') + return result + + def get_puzzle(self): + return referee.curry(self.curried_parameters_for_our_puzzle( + "GET_PUZZLE", + True, + self.move, + self.split, + self.validation_program_hash + )) + + def SpendMove(self, password, move_to_make, split, validation_program_hash): + """ + returns (solution, new RefereeWrap) + """ + print(f"MOVE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"MOVE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + curried_parameters = self.curried_parameters_for_our_puzzle( + "SPEND_MOVE", + False, + move_to_make, + split, + validation_program_hash + ) + print(f"MOVE referee curried parameters {curried_parameters}") + new_puzzle_hash = referee.curry(curried_parameters).tree_hash() + print(f"MOVE new puzzle hash {Program.to(new_puzzle_hash)}") + solution = Program.to([move, move_to_make, split, validation_program_hash, self.mover_puzzle, + [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + everything_else_hash = Program.to([self.move, self.split, self.coin.amount, self.timeout, + self.max_move_size, self.mover_puzzle.tree_hash(), self.waiter_puzzle.tree_hash(), + referee.tree_hash()]).tree_hash() + return (solution, RefereeWrap(coin, self.coin.parent_coin_info, self.validation_program_hash, everything_else_hash, + validation_program_hash, move_to_make, split, self.timeout, self.max_move_size, + self.waiter_puzzle, self.mover_puzzle)) + + def SpendAccuse(self, password): + """ + returns (solution, RefereeAccuse) + """ + print(f"ACCUSE starting with puzzle hash {Program.to(self.get_puzzle().tree_hash())}") + print(f"ACCUSE parent_id {Program.to(self.coin.parent_coin_info)}") + print(f"ACCUSE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"ACCUSE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + new_puzzle_hash = referee_accuse.curry([ + self.parent_validation_program_hash, + self.validation_program_hash, + self.move, + self.split, + self.coin.amount, + self.timeout, + self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash() + ]).tree_hash() + solution = Program.to([accuse, self.grandparent_id, self.parent_validation_program_hash, + self.parent_everything_else_hash, self.mover_puzzle, [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + return (solution, RefereeAccuseWrap(coin, self.parent_validation_program_hash, self.validation_program_hash, + self.move, self.split, self.timeout, self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash())) + + def SpendTimeout(self): + """ + returns (solution, movercoinid, waitercoinid) + """ + movercoinid = Coin(self.coin.name(), self.mover_puzzle.tree_hash(), self.split).name() + waitercoinid = Coin(self.coin.name(), self.waiter_puzzle.tree_hash(), + self.coin.amount - self.split).name() + return (Program.to((timeout, 0)), movercoinid, waitercoinid) + +@dataclass +class RefereeAccuseWrap: + coin: Any + old_validation_puzzle_hash: Any + new_validation_puzzle_hash: Any + move: Any + split: Any + timeout: Any + accused_puzzle_hash: Any + accuser_puzzle_hash: Any + + def get_puzzle(self): + return referee_accuse.curry([self.old_validation_puzzle_hash, self.new_validation_puzzle_hash, + self.move, self.split, self.coin.amount, self.timeout, self.accused_puzzle_hash, + self.accuser_puzzle_hash]) + + def SpendTimeout(self): + """ + returns (solution, coinid) + """ + coin = Coin(self.coin.name(), self.accuser_puzzle_hash, self.coin.amount) + return (Program.to(0), coin.name()) + + def SpendDefend(self, validation_program_reveal, validation_program_solution): + """ + returns (solution, coinid) + """ + solution = Program.to([validation_program_reveal, validation_program_solution]) + coin = Coin(self.coin.name(), self.accused_puzzle_hash, self.coin.amount) + return (solution, coin.name()) + +@pytest.mark.asyncio +@pytest.mark.parametrize('amove', [0, 1, 2]) +@pytest.mark.parametrize('bmove', [0, 1, 2]) +async def test_rps(amove, bmove, setup_sim): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = int_to_bytes(60 + amove) + alice_image = sha(alice_preimage) + bob_preimage = int_to_bytes(60 + bmove) + bob_image = sha(bob_preimage) + alice_move = int_to_bytes(amove) + nil = Program.to(0) + + # (mod (password . conditions) (if (= password 'alice') conditions (x))) + alice_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0185616c69636580ffff0103ffff01ff088080ff0180')) + alice_puzzle_hash = alice_puzzle.tree_hash() + # (mod (password . conditions) (if (= password 'bob') conditions (x))) + bob_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0183626f6280ffff0103ffff01ff088080ff0180')) + bob_puzzle_hash = bob_puzzle.tree_hash() + + async with setup_sim as (sym, client): + acs = Program.to(1) + acs_hash = acs.tree_hash() + await sym.farm_block(acs_hash) + mycoin = (await client.get_coin_records_by_puzzle_hashes([acs_hash], include_spent_coins = False))[0].coin + # make a coin for a game + referee = bootstrap_referee(mycoin.name(), MOD_A.tree_hash(), 2, total, 1000, 50, alice_puzzle, bob_puzzle) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(mycoin, acs, Program.to([[51, referee.coin.puzzle_hash, + referee.coin.amount]]))], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse Bob of cheating (negative test, should fail) + solution, accuse = referee.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_MY_PARENT_ID_FAILED + # timeout too early fail + solution, alice_reward_id, bob_reward_id = referee.SpendTimeout() + spend = SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # timeout succeeds + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == 2 + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == total - 2 + await sym.rewind(savepoint) + # Alice makes an illegally large move, fails + solution, ref2 = referee.SpendMove('alice', bytes(100), 0, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with negative split, fails + solution, ref2 = referee.SpendMove('alice', 'abc', -1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with split greater than amount, fails + solution, ref2 = referee.SpendMove('alice', 'abc', referee.coin.amount + 1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice move 1 commit to image + bpuz = MOD_B.curry(alice_image) + solution, ref2 = referee.SpendMove('alice', alice_image, 0, bpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuse Alice of cheating + solution, accuse = ref2.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint2 = sym.block_height + # Alice accusation defend, gets everything + solution, reward_id = accuse.SpendDefend(MOD_A, nil) + print(solution) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == alice_puzzle_hash + await sym.rewind(savepoint2) + # accusation timeout too early fail + solution, reward_id = accuse.SpendTimeout() + spend = SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # accusation timeout succeed, Bob gets everything + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Bob move 2 commit to image + cpuz = MOD_C.curry([alice_image, bob_image]) + solution, ref3 = ref2.SpendMove('bob', bob_image, 0, cpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse + solution, accuse = ref3.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(bpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin = (await client.get_coin_records_by_names([reward_id], include_spent_coins = + False))[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Alice reveals wrong preimage + alice_bad_preimage = int_to_bytes(61 + amove) + dpuz = MOD_D.curry([(amove + 1) % 3, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends, fails + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Alice move 3 reveal preimage + dpuz = MOD_D.curry([alice_move, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.rewind(savepoint) + # Bob move 4 reveal wrong preimage + bob_bad_preimage = int_to_bytes(121 + amove) + solution, ref5 = ref4.SpendMove('bob', bob_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Bob attempts defense with wrong validation program, fails + solution, reward_id = accuse.SpendDefend(acs, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + if amove == bmove: + # Bob move 4 gives wrong split + solution, ref5 = ref4.SpendMove('bob', bob_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Bob move 4 reveal preimage + solution, ref5 = ref4.SpendMove('bob', bob_preimage, alice_final, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice attempts move, fails + solution, ref6 = ref5.SpendMove('alice', nil, 0, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # timeout, split correct + sym.pass_time(2000) + await sym.farm_block() + solution, alice_reward_id, bob_reward_id = ref5.SpendTimeout() + spend = SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + if alice_final != 0: + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == alice_final + else: + assert len(await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False)) == 0 + if alice_final != ref5.coin.amount: + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == ref5.coin.amount - alice_final + else: + assert len(await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False)) == 0 + await sym.rewind(savepoint) + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert (status, err) == (MempoolInclusionStatus.SUCCESS, None) diff --git a/resources/tests/game-referee-after-cl21/testrockpaperscissors.py b/resources/tests/game-referee-after-cl21/testrockpaperscissors.py new file mode 100644 index 000000000..ed45dbccc --- /dev/null +++ b/resources/tests/game-referee-after-cl21/testrockpaperscissors.py @@ -0,0 +1,48 @@ +import hashlib + +from hsms.streamables.program import Program +from hsms.puzzles.load_clvm import load_clvm + +from clvm.EvalError import EvalError + + +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha256(blob:bytes) -> bytes: + return hashlib.sha256(blob).digest() + +def testrps(amove, bmove): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = Program.to(60 + amove) + bob_preimage = Program.to(60 + bmove) + alice_image = sha256(alice_preimage.atom) + bob_image = sha256(bob_preimage.atom) + alice_move = Program.to(amove) + + cd = MOD_D.curry(alice_move, bob_image) + assert cd.run([total, bob_preimage, b'', alice_final, b'j']).atom == b'j' + cc = MOD_C.curry(alice_image, bob_image) + assert cc.run([total, alice_preimage, cd.tree_hash(), 0, b'j']).atom == b'j' + cb = MOD_B.curry(alice_image) + assert cb.run([total, bob_image, cc.tree_hash(), 0, b'j']).atom == b'j' + assert MOD_A.run([total, alice_image, cb.tree_hash(), 0, b'j']).atom == b'j' + +def testall(): + for i in range(3): + for j in range(3): + testrps(i, j) + +if __name__ == '__main__': + testall() diff --git a/resources/tests/game-referee-in-cl21/handcalc.clinc b/resources/tests/game-referee-in-cl21/handcalc.clinc new file mode 100644 index 000000000..6317733f4 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/handcalc.clinc @@ -0,0 +1,140 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun find_flush_inner (suits last count) + (if (not suits) + 0 + (if (= (f suits) last) + (if (= count 4) + last + (find_flush_inner (r suits) last (+ count 1)) + ) + (find_flush_inner (r suits) (f suits) 1) + ) + ) + ) + ; returns the flush suit or 0 if there isn't any + ; suits must be clustered/sorted + (defun find_flush (suits) + (find_flush_inner (sort (lambda (x y) (deep> x y)) suits) 0 0) + ) + (defun straight_high_inner (ranks started_ace last count) + (if (not ranks) + ; at the end of the list + (if (logand (= last 2) (= count 4) started_ace) + ; ace to five + 5 + ; no straight + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner ranks (= (f ranks) 14) 0 0) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (c count last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (c (c count last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush (map rest cards)) + max_flush (if (not fsuit) + 0 + (assign-lambda + fnosuits + (sort + (lambda (x y) (deep> x y)) + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + ) + + fsh (straight_high fnosuits) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice fnosuits 5)) + ) + ) + ) + nosuits (sort (lambda (x y) (deep> x y)) (map first cards)) + sh (straight_high nosuits) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort (lambda (x y) (deep> x y)) (group_by_count nosuits)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + (max (lambda (x y) (deep< x y)) (list max_flush max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/handcalc_a.clinc b/resources/tests/game-referee-in-cl21/handcalc_a.clinc new file mode 100644 index 000000000..06c326392 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/handcalc_a.clinc @@ -0,0 +1,256 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun hand_compare (a b) + (if (= (f a) (f b)) + (if (r a) + (hand_compare (r a) (r b)) + 0 + ) + (- (* 2 (> (f a) (f b))) 1) + ) + ) + (defun hand< (a b) + (= (hand_compare a b) -1) + ) + (defun merge (a b) + (if (not a) + b + (if (not b) + a + (if (> (f a) (f b)) + (c (f a) (merge (r a) b)) + (c (f b) (merge a (r b))) + ) + ) + ) + ) + ; Sorts atoms into descending order + ; This is optimized for sorting short lists + ; A more general function would return a list of lists of ascending sizes + ; to be merged + (defun atomsort ((@ firstpos (first @ secondpos (second @ thirdpos (third . remaining))))) + (if firstpos + (if secondpos + (if thirdpos + (assign-lambda + mylist + (if (> first second) + (if (> second third) + (list first second third) + (if (> first third) + (list first third second) + (list third first second) + ) + ) + (if (> first third) + (list second first third) + (if (> second third) + (list second third first) + (list third second first) + ) + ) + ) + (merge mylist (atomsort remaining)) + ) + (if (> first second) + firstpos + (list second first) + ) + ) + firstpos + ) + 0 + ) + ) + (defun count_suits_2 ((@ suits (firstsuit . remaining))) + (if (not suits) + (c (c 0 0) (c 0 0)) + (assign-lambda ((@ cd (clubs . diamonds)) . (@ hs (hearts . spades))) (count_suits remaining) + (if (= firstsuit 1) + (c (c (+ clubs 1) diamonds) hs) + (if (= firstsuit 2) + (c (c clubs (+ diamonds 1)) hs) + (if (= firstsuit 3) + (c cd (c (+ hearts 1) spades)) + (c cd (c hearts (+ spades 1))) + ) + ) + ) + ) + ) + ) + (defun find_flush_2 (suits) + (assign-lambda ((clubs . diamonds) . (hearts . spades)) (count_suits suits) + (if (> clubs 4) + 1 + (if (> diamonds 4) + 2 + (if (> hearts 4) + 3 + (if (> spades 4) + 4 + 0 + ) + ) + ) + ) + ) + ) + (defun count_suits (suits) + (if suits + (+ (count_suits (r suits)) (ash 1 (* 4 (- (f suits) 1)))) + 0 + ) + ) + (defun find_flush (suits) + (assign-lambda + myvals (count_suits suits) + (if (> (logand myvals 0xF000) 0x4000) + 4 + (if (> (logand myvals 0x0F00) 0x0400) + 3 + (if (> (logand myvals 0x00F0) 0x0040) + 2 + (if (> (logand myvals 0x0F) 0x04) + 1 + 0 + ) + ) + ) + ) + ) + ) + (defun straight_high_inner (ranks last count) + (if (not ranks) + (if (logand (= last 2) (= count 4)) + ; maybe ace to five + 5 + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (assign-lambda high (straight_high_inner ranks 0 0) + (if (= high 5) + (* (= (f ranks) 14) 5) + high + ) + ) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (logior (lsh count 4) last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign-inline val (group_by_count_inner (r items) (f items) 1) + (c (logior (lsh count 4) last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush (map rest cards)) + max_flush (if (not fsuit) + (list 0) + (assign-lambda + flushcards + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + flushranks (atomsort flushcards) + fsh (straight_high flushranks) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice flushranks 5)) + ) + ) + ) + ranks (atomsort (map first cards)) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + (list 0) + ) + groups (map + (lambda (myval) (c (lsh myval -4) (logand myval 0x0F))) + (atomsort (group_by_count ranks)) + ) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + ; max of max_flush max_straight and max_group + (if (> (f max_flush) (f max_straight)) + (if (> (f max_flush) (f max_group)) + max_flush + max_group + ) + (if (> (f max_straight) (f max_group)) + max_straight + max_group + ) + ) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp new file mode 100644 index 000000000..8df629518 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp @@ -0,0 +1,28 @@ +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include deep_compare.clinc) + + (map + (lambda ((want_cmp_val cmp_a cmp_b)) + (= (deep_compare cmp_a cmp_b) want_cmp_val) + ) + (q + (0 0 0) + (-1 () (1 14 5 4 3 2)) + (1 (1 14 5 4 3 2) ()) + (-1 "X" (1 2)) + (1 (1 2) "X") + (0 (3 2) (3 2)) + (-1 (3 1) (3 3)) + (1 (3 3) (3 1)) + (-1 (1 1) (2 1)) + (1 (3 1) (2 2)) + (-1 (2 2) (3 1)) + ) + ) + ) diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex new file mode 100644 index 000000000..cb3eb0bf7 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff0e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff01ffff80ff80ff8080ffff81ffff80ffff01ff0eff05ff04ff03ff028080ffff01ffff01ff0eff05ff04ff03ff0280ff8080ffff81ffff58ffff01ff028080ffff01ffff01ff0280ff5880ffff80ffff03ff0280ffff03ff028080ffff81ffffff03ff0180ffff03ff038080ffff01ffff03ff0380ffff03ff018080ffff81ffffff01ff0180ffff02ff018080ffff01ffff03ff0180ffff02ff028080ffff81ffffff02ff0280ffff03ff01808080ffff04ffff0180ff808080808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff02ff0cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff0cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff0cffff04ff02ffff04ff2bffff04ff5bff8080808080ff1380ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.sym b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.sym new file mode 100644 index 000000000..3d2e104b3 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.sym @@ -0,0 +1 @@ +{"026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160_arguments": "(() (want_cmp_val cmp_a cmp_b))", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clsp", "__chia__main_arguments": "()", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_left_env": "1", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687": "deep_compare", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160_left_env": "1", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687_arguments": "(a b)", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743": "letbinding_$_58", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743_left_env": "1", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687_left_env": "1", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b": "map-with-rest", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_arguments": "(F L R)", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743_arguments": "((a_$_43 b_$_44) inner_result)", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160": "lambda_$_57"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp new file mode 100644 index 000000000..2ed3fbbcc --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp @@ -0,0 +1,9 @@ +(mod (X) + (include *standard-cl-21*) + (include map.clinc) + (include prepend.clinc) + (include print.clinc) + (include permutations.clinc) + + (permutations X) + ) diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex new file mode 100644 index 000000000..ad4e2fba6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff1effff04ff02ffff04ff05ff80808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff14ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff1effff04ff02ffff04ffff02ff14ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff1cffff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ffff04ff09ff0b80ff02ffff03ff05ffff01ff02ffff01ff02ff1cffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.sym b/resources/tests/game-referee-in-cl21/smoke_test_permutations.sym new file mode 100644 index 000000000..c53c294de --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_permutations.sym @@ -0,0 +1 @@ +{"0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom) x)", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b": "map-with-rest", "cbc879391ee3747e5a0a6457916b75a38118f0febf74e14983e66c8105ffb9c8": "permutations_inner", "f6344fd0045418e460a57d88fc880464d12fcafb3b3c3adbc52e0e39672bf0c8": "letbinding_$_387", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf_arguments": "(vals)", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/smoke_test_permutations.clsp", "cbc879391ee3747e5a0a6457916b75a38118f0febf74e14983e66c8105ffb9c8_arguments": "(pre post agg)", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b_arguments": "(a b)", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf_left_env": "1", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_arguments": "(F L R)", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_left_env": "1", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b": "prepend", "cbc879391ee3747e5a0a6457916b75a38118f0febf74e14983e66c8105ffb9c8_left_env": "1", "__chia__main_arguments": "(X)", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf": "permutations", "f6344fd0045418e460a57d88fc880464d12fcafb3b3c3adbc52e0e39672bf0c8_left_env": "1", "f6344fd0045418e460a57d88fc880464d12fcafb3b3c3adbc52e0e39672bf0c8_arguments": "((pre_$_383 post_$_384 agg_$_385) myatom newrest)", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_388", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.clsp b/resources/tests/game-referee-in-cl21/smoke_test_sort.clsp new file mode 100644 index 000000000..59b8a886e --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_sort.clsp @@ -0,0 +1,11 @@ +(mod (X) + (include *standard-cl-21*) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include reverse.clinc) + (include print.clinc) + + (sort (lambda (a b) (> b a)) X) + ) diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex new file mode 100644 index 000000000..476b5f74e --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff12ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff3e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ffff04ffff01ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff10ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff18ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffff02ff18ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff2affff04ff02ffff04ffff06ff0180ffff04ffff02ff14ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff3affff04ff02ffff04ff03ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff3cffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ff16ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff16ffff04ff02ffff04ff80ffff04ff05ff8080808080ff15ff17ff0b80ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.sym b/resources/tests/game-referee-in-cl21/smoke_test_sort.sym new file mode 100644 index 000000000..2a0f8ed38 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_sort.sym @@ -0,0 +1 @@ +{"aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47": "letbinding_$_108", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/smoke_test_sort.clsp", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b_left_env": "1", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1_left_env": "1", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53_arguments": "(mylist)", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4": "letbinding_$_107", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b": "lambda_$_106", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b_arguments": "(() a b)", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3": "sort", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47_left_env": "1", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa": "merge", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8": "prepend", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8_arguments": "(a b)", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3_arguments": "(@ everything (rest aggl aggr))", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3_arguments": "(myless mylist)", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8_left_env": "1", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299_left_env": "1", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3_left_env": "1", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140_left_env": "1", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3": "split_inner", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa_left_env": "1", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4_arguments": "((myless_$_91 mylist_$_92) (a b))", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa_arguments": "(myless a b)", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140_arguments": "(vals)", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3_left_env": "1", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4_left_env": "1", "__chia__main_arguments": "(X)", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140": "reverse", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53": "split", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299": "reverse_inner", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1": "merge_inner", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299_arguments": "(reversed rest)", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53_left_env": "1", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47_arguments": "(((myless_$_91 mylist_$_92) (a b)) sa sb)", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1_arguments": "(myless A B agg)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/spacehandcalc.clinc b/resources/tests/game-referee-in-cl21/spacehandcalc.clinc new file mode 100644 index 000000000..3bfae65ca --- /dev/null +++ b/resources/tests/game-referee-in-cl21/spacehandcalc.clinc @@ -0,0 +1,104 @@ + +; ranks are 1-13 with 1 being two, 12 being king, and 13 being ace +; there are no suits, flushes, or ace-to-four straights +; takes a list of card ranks and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; all sorting is done highest to lowest +( + (include *standard-cl-22*) + (include sort.clinc) + (include deep_compare.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include max.clinc) + (defconstant FIVE_OF_A_KIND 10) + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun straight_high_inner (ranks last count) + (if (not ranks) + ; at the end of the list + 0 + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner (ranks (= (f ranks) 13) 0 0)) + ) + (defun group_by_count_inner (items last count) + (if (not items) + 0 + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (if last + (c (c count last) val) + val + ) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items 0 0) + ) + (defun space_hand_calc (cards) + (assign + rest (lambda (x) (r x)) + greater (lambda (x y) (> x y)) + ranks (sort greater cards) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort deep> (group_by_count ranks)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (if (= top_count 4) + (c FOUR_OF_A_KIND (slice topcards 2)) + (c FIVE_OF_A_KIND (slice topcards 1)) + ) + ) + ) + ) + (max deep< (list max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.clsp b/resources/tests/game-referee-in-cl21/test_handcalc.clsp new file mode 100644 index 000000000..16c46f664 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc.clsp @@ -0,0 +1,379 @@ + +(mod () + (include *standard-cl-21*) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include sort.clinc) + (include max.clinc) + (include handcalc.clinc) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + firstval (handcalc firstarg) + secondval (handcalc secondarg) + (assert + (a myfunc (list firstval secondval)) + (deep= firstval (handcalc (reverse firstarg))) + (deep= secondval (handcalc (reverse secondarg))) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex new file mode 100644 index 000000000..441ac847b --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff8200feffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff0180808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0104ffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff01808080808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff0108ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0108ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff010dffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff010effff010480ffff04ffff04ffff010dffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0105ffff010480ffff04ffff04ffff0104ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff0180808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0102ffff010380ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0106ffff010380ffff04ffff04ffff0106ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0106ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0109ffff010480ffff04ffff04ffff0108ffff010180ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0105ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff01808080808080ff808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080ffff04ffff01ffffffffffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff8200a0ffff04ff02ffff04ffff06ff0180ffff04ffff02ff40ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff010180ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ff0bffff01ff02ffff01ff02ff8200f0ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffffff02ff8200f0ffff04ff02ffff04ff80ffff04ff05ff8080808080ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200a8ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff8200e8ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff8200b8ffff04ff02ffff04ffff06ff0180ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ff8080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ff0bffff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff80808080808080ff0180ffff01ff02ffff01ff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff808080808080ff018080ff0180ff02ffff03ffff02ff44ffff04ff02ffff04ffff04ffff018c736c69636520696e70757473ffff04ffff01866e796c697374ffff04ff0bff80808080ffff04ffff20ff0b80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200f8ffff04ff02ffff04ffff06ff0580ffff04ffff11ff0bffff010180ff808080808080ff018080ff0180ffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff8200a4ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff8200a4ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200e4ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff8200acffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffff02ff8200b4ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ff02ffff03ffff20ff1780ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ff0bffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ffff05ff1780ffff04ffff06ff1780ff808080808080ff0180ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ff808080808080ff018080ff0180ff018080ff0180ffff02ff8200ecffff04ff02ffff04ff05ffff04ff13ffff04ff1bff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ffff03ffff09ff17ffff010480ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff018080ff0180ff018080ff0180ff02ff8200bcffff04ff02ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff05ff8080808080ffff01ff80ff8080808080ffffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff02ffff03ffff18ffff09ff17ffff010280ffff09ff2fffff010480ff0b80ffff01ff02ffff01ff0105ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff17ffff05ff058080ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ff17ffff04ff2fff80808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ffff11ff17ffff01018080ffff01ff02ffff01ff02ffff03ffff09ff2fffff010480ffff01ff02ffff01ff10ff17ffff010380ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff10ff2fffff010180ff80808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff0101ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff8200a2ffff04ff02ffff04ff05ffff04ffff09ff09ffff010e80ffff01ff80ff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff04ffff04ff17ff0b80ffff018080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff0180ffff01ff02ffff01ff02ff8200b2ffff04ff02ffff04ffff06ff0180ffff04ffff02ff52ffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff8080808080ff018080ff0180ff018080ff0180ffff04ffff04ff2dff1580ff0b80ff02ff52ffff04ff02ffff04ff05ffff04ff09ffff01ff808080808080ffffff02ff5affff04ff02ffff04ff03ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200aa80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ea80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ff808080808080ff131bffff02ff8200faffff04ff02ffff04ff03ffff04ffff02ff8200fcffff04ff02ffff04ffff02ff8200e8ffff04ff02ffff04ff17ffff04ff09ffff01ff808080808080ff80808080ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ba80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200e8ffff04ff02ffff04ff0bffff04ff09ffff01ff808080808080ff8080808080ff808080808080ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff8200f6ffff04ff02ffff04ff03ffff04ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff8200e6ffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200a680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bffff01808080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff11ffff04ffff0180ff808080808080ff8080808080ff8080808080ff018080ff0180ffff04ffff02ff8200e2ffff04ff02ffff04ff17ff80808080ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200b680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200f2ffff04ff02ffff04ff17ff80808080ff8080808080ff80808080808080ffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff09ff09ff1b80ffff01ff02ffff0113ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff56ffff04ff02ffff04ff03ffff04ffff02ff8200e2ffff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ff0bffff01ff02ffff01ff04ffff0109ffff04ff0bffff01808080ff0180ffff01ff02ffff01ff04ffff0106ffff02ff8200f8ffff04ff02ffff04ff15ffff04ffff0105ff808080808080ff018080ff0180ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff4effff04ff02ffff04ff03ffff04ffff02ffff03ff17ffff01ff02ffff01ff04ffff0105ffff04ff17ffff01808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff04ff4fffff04ff81afffff04ffff02ff8200e8ffff04ff02ffff04ff59ffff04ff2fffff01ff808080808080ff8080808080808080ffffff02ff8200aeffff04ff02ffff04ff03ffff04ffff02ffff03ffff09ff27ffff010180ffff01ff02ffff01ff04ffff0101ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0105ff808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ff27ffff010280ffff01ff02ffff01ff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0102ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0104ff808080808080ff0180ffff01ff02ffff01ff04ffff0103ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff27ffff010380ffff01ff02ffff01ff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0104ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff0180ffff01ff02ffff01ff04ffff0107ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff04ffff0108ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff8080808080ffff02ff5cffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ee80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ff29ffff04ff15ffff04ff0bff80808080ff8080808080ff02ff8200e0ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ff8200beffff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff15ff80808080ffff04ffff02ff4affff04ff02ffff04ff2dff80808080ff808080808080ffff02ffff03ffff02ff11ffff04ff0bffff04ff17ff80808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff0bffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff29ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff17ffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff59ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ff79ffff01ff02ffff01ff02ff5effff04ff02ffff04ff79ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff02ffff03ff03ffff01ff02ffff01ff02ff5effff04ff02ffff04ff03ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.sym b/resources/tests/game-referee-in-cl21/test_handcalc.sym new file mode 100644 index 000000000..4ff5ca1eb --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc.sym @@ -0,0 +1 @@ +{"dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6_left_env": "1", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108": "straight_high_inner", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36_left_env": "1", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3_arguments": "(((myless_$_453 mylist_$_454) (a b)) sa sb)", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367_left_env": "1", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd_left_env": "1", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd_arguments": "(myless mylist)", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9_left_env": "1", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09_arguments": "(a b)", "1c2f95563ff25508afc464b19cd91787c95ac0b12f1d4fa16addeaa6335aac8d_arguments": "((((((cards_$_473) first rest) fsuit nosuits) max_flush sh groups) max_straight (top_count . top_card) (second_count . second_card) topcards) max_group)", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8_arguments": "(() x y)", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958_arguments": "(() x y)", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004": "letbinding_$_481", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca_arguments": "(process remaining init)", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65": "merge", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e": "lambda_$_486", "973ed02dde4588cd7699bdec8c1138e788edf49380ca7a8c62c74ad021bf8022_arguments": "((((cards_$_473) first rest) fsuit nosuits) fnosuits)", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661": "letbinding_$_479", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66": "runtests", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca_left_env": "1", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c_left_env": "1", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6": "straight_high", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b_arguments": "(F L R)", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108_arguments": "(ranks started_ace last count)", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060_arguments": "(suits last count)", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897": "split_inner", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e_left_env": "1", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba": "deep>", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367_arguments": "(a b)", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9": "reverse", "b131c2e07b1152ba1bd67a5398a6b58cde3020e01fa510f0f7c3cd502fcdb30d_left_env": "1", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485_arguments": "(myless A B agg)", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901_left_env": "1", "6776e296095747790c1a208caea4e4b8633e2c146890367f13a0238f42b28c87_left_env": "1", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25_arguments": "((process_$_431 remaining_$_432 init_$_433) next)", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3_left_env": "1", "20f4eca5a09be558c75518290c48d6aad0e4e8306e79cf03e92b8ca828d35f99": "runtests_inner", "c4f6f8551c01bbcf52ab1fd2b92333649110b28aee8570a9422e2b3a671fe94b_arguments": "((((cards_$_473) first rest) fsuit nosuits) max_flush sh groups)", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901_arguments": "(mylist)", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27_arguments": "(myless best_so_far mylist)", "ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f_arguments": "(a b)", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_left_env": "1", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108_left_env": "1", "6776e296095747790c1a208caea4e4b8633e2c146890367f13a0238f42b28c87_arguments": "(((((cards_$_473) first rest) fsuit nosuits) max_flush sh groups) max_straight (top_count . top_card) (second_count . second_card) topcards)", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9_arguments": "((items_$_469 last_$_470 count_$_471) val)", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25_left_env": "1", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6_arguments": "(ranks)", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d": "deep<", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25": "letbinding_$_480", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b": "map-with-rest", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9": "letbinding_$_484", "8c4576eb20d2f8cc795c065e3a585703145c1f6beff372bf37b4634ad785adc8": "letbinding_$_488", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65_left_env": "1", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060_left_env": "1", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba_arguments": "(a b)", "8c4576eb20d2f8cc795c065e3a585703145c1f6beff372bf37b4634ad785adc8_left_env": "1", "__chia__main_arguments": "()", "b131c2e07b1152ba1bd67a5398a6b58cde3020e01fa510f0f7c3cd502fcdb30d": "letbinding_$_485", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3": "find_flush", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9_arguments": "(vals)", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958": "lambda_$_494", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8": "lambda_$_498", "b16167d2466d1fb9c6fd4b5636fa809f866e9b7a0a698f1a18ffa308d7280c42": "letbinding_$_499", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c": "slice", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3": "letbinding_$_482", "1c2f95563ff25508afc464b19cd91787c95ac0b12f1d4fa16addeaa6335aac8d": "letbinding_$_497", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_arguments": "(R P)", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d_left_env": "1", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897_arguments": "(@ everything (rest aggl aggr))", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263_arguments": "(myless mylist)", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed_arguments": "(items last count)", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263": "sort", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66_arguments": "tests", "b131c2e07b1152ba1bd67a5398a6b58cde3020e01fa510f0f7c3cd502fcdb30d_arguments": "((cards_$_473) first rest)", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485": "merge_inner", "973ed02dde4588cd7699bdec8c1138e788edf49380ca7a8c62c74ad021bf8022": "letbinding_$_491", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661_left_env": "1", "973ed02dde4588cd7699bdec8c1138e788edf49380ca7a8c62c74ad021bf8022_left_env": "1", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_handcalc.clsp", "ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f_left_env": "1", "20f4eca5a09be558c75518290c48d6aad0e4e8306e79cf03e92b8ca828d35f99_arguments": "((myfunc firstarg secondarg . remaining))", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374_left_env": "1", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65_arguments": "(myless a b)", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27": "max_inner", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897_left_env": "1", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27_left_env": "1", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed": "group_by_count_inner", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09": "prepend", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854_left_env": "1", "1c2f95563ff25508afc464b19cd91787c95ac0b12f1d4fa16addeaa6335aac8d_left_env": "1", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e": "handcalc", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9_left_env": "1", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958_left_env": "1", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3_arguments": "(suits)", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09_left_env": "1", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd": "max", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed_left_env": "1", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661_arguments": "((a_$_404 b_$_405) inner_result)", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca": "filtermap", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36": "lambda_$_493", "c4f6f8551c01bbcf52ab1fd2b92333649110b28aee8570a9422e2b3a671fe94b_left_env": "1", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa_arguments": "(items)", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e": "print", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36_arguments": "((fsuit) (card_rank . card_suit))", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e_arguments": "(cards)", "b16167d2466d1fb9c6fd4b5636fa809f866e9b7a0a698f1a18ffa308d7280c42_arguments": "(((myfunc_$_474 firstarg_$_475 secondarg_$_476 . remaining_$_477)) firstval secondval)", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d_arguments": "(a b)", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374": "reverse_inner", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c_arguments": "(mylist count)", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485_left_env": "1", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa": "group_by_count", "b16167d2466d1fb9c6fd4b5636fa809f866e9b7a0a698f1a18ffa308d7280c42_left_env": "1", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba_left_env": "1", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b_left_env": "1", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6_left_env": "1", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3_left_env": "1", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa_left_env": "1", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854": "lambda_$_487", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004_arguments": "((myless_$_453 mylist_$_454) (a b))", "dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6_arguments": "(((((cards_$_473) first rest) fsuit nosuits) fnosuits) fsh)", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e_arguments": "(() x)", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e_left_env": "1", "6776e296095747790c1a208caea4e4b8633e2c146890367f13a0238f42b28c87": "letbinding_$_496", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263_left_env": "1", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901": "split", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8_left_env": "1", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66_left_env": "1", "c4f6f8551c01bbcf52ab1fd2b92333649110b28aee8570a9422e2b3a671fe94b": "letbinding_$_490", "dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6": "letbinding_$_495", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004_left_env": "1", "ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f": "deep=", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060": "find_flush_inner", "20f4eca5a09be558c75518290c48d6aad0e4e8306e79cf03e92b8ca828d35f99_left_env": "1", "8c4576eb20d2f8cc795c065e3a585703145c1f6beff372bf37b4634ad785adc8_arguments": "(((cards_$_473) first rest) fsuit nosuits)", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854_arguments": "(() x)", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367": "deep_compare", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374_arguments": "(reversed rest)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_handcalc_b.clsp b/resources/tests/game-referee-in-cl21/test_handcalc_b.clsp new file mode 100644 index 000000000..674bbd414 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc_b.clsp @@ -0,0 +1,377 @@ + +(mod () + (include *standard-cl-21*) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include handcalc.clinc) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + firstval (handcalc firstarg) + secondval (handcalc secondarg) + (assert + (a myfunc (list firstval secondval)) + (deep= firstval (handcalc (reverse firstarg))) + (deep= secondval (handcalc (reverse secondarg))) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_library_basics.py b/resources/tests/game-referee-in-cl21/test_library_basics.py new file mode 100644 index 000000000..926ddde7a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_library_basics.py @@ -0,0 +1,165 @@ +import os +import pytest +import random +from itertools import permutations +from typing import List +#from hsms.streamables.program import Program +#from steprun import diag_run_clvm, compile_module_with_symbols +#from lib.program import Program +from pathlib import Path +from clvm_rs import Program +from lib.steprun import diag_run_clvm, compile_module_with_symbols +from clvm_tools_rs import get_version + +print(f"clvm_tools_rs version is {get_version()}") +#include_dirs = os.getcwd() +include_dirs = [Path(__file__).parent, Path(__file__).parent.parent / "lib"] +Program.set_run_unsafe_max_cost(11000000000) + +print(f"XXX: {include_dirs}") +compile_module_with_symbols(include_dirs, 'smoke_test_deep_compare.clsp') +compare_program = Program.from_bytes(bytes.fromhex(open('smoke_test_deep_compare.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'smoke_test_sort.clsp') +sort_program = Program.from_bytes(bytes.fromhex(open('smoke_test_sort.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_sort.clsp') +test_sort_program = Program.from_bytes(bytes.fromhex(open('test_sort.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_permutations.clsp') +test_permutations_program = Program.from_bytes(bytes.fromhex(open('test_permutations.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_reverse.clsp') +test_reverse_program = Program.from_bytes(bytes.fromhex(open('test_reverse.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_prepend.clsp') +test_prepend_program = Program.from_bytes(bytes.fromhex(open('test_prepend.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_range.clsp') +test_range_program = Program.from_bytes(bytes.fromhex(open('test_range.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'smoke_test_permutations.clsp') +smoke_test_permutations_program = Program.from_bytes(bytes.fromhex(open('smoke_test_permutations.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_handcalc.clsp') +test_handcalc_program = Program.from_bytes(bytes.fromhex(open('test_handcalc.clvm.hex').read())) + +def as_atom_list(prg: Program) -> List[bytes]: + """ + Pretend `prg` is a list of atoms. Return the corresponding + python list of atoms. + + At each step, we always assume a node to be an atom or a pair. + If the assumption is wrong, we exit early. This way we never fail + and always return SOMETHING. + """ + items = [] + obj = prg + while True: + pair = obj.pair + if pair is None: + break + atom = pair[0].atom + if atom is None: + break + items.append(atom) + obj = pair[1] + return items + +def test_smoke_compare(): + compare_program.run(Program.to([])) + +def test_handcalc(): + diag_run_clvm(test_handcalc_program, Program.to([]), 'test_handcalc.sym') + +def proper_list_inner(result,cl): + if hasattr(cl, 'pair') and cl.pair is not None: + result.append(cl.pair[0]) + return proper_list_inner(result,cl.pair[1]) + else: + return result + +def proper_list(cl): + result = [] + return proper_list_inner(result,cl) + +def int_list(cl): + return [Program.to(x).as_int() for x in as_atom_list(Program.to(cl))] + +def de_none_list(l): + return [x if x is not None else [] for x in l] + +def with_random_lists(n,f): + for length in range(n): # 0-10 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + f(orig_list) + +def test_prepend(): + for length1 in range(5): + list_1 = list(range(length1)) + for length2 in range(length1): + prepend_result = test_prepend_program.run([Program.to(list_1[:length2]),Program.to(list_1[length2:])]) + assert list_1 == int_list(prepend_result) + +def test_reverse(): + def test_reverse_list(l): + rev_args = Program.to([l]) + reversed_result = Program.to(list(reversed(l))) + reversed_by_prog = test_reverse_program.run(rev_args) + assert reversed_result == reversed_by_prog + + with_random_lists(10,test_reverse_list) + +def test_range(): + for length in range(10): + want_list = list(range(length)) + result = test_range_program.run(Program.to([length])) + assert want_list == result + +def do_test_permutations_of_size_n(n): + try_list = [random.randint(0,100) for x in range(n)] + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = smoke_test_permutations_program.run(Program.to([try_list])) + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_permutations_0(): + do_test_permutations_of_size_n(0) + +def test_permutations_1(): + do_test_permutations_of_size_n(1) + +def test_permutations_2(): + n = 2 + all_a_string = 0x616161616161 + all_b_string = 0x626262626262 + for try_list in [[all_a_string,all_b_string], [all_b_string,all_a_string]]: + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = diag_run_clvm(smoke_test_permutations_program, Program.to([try_list]), 'smoke_test_permutations.sym') + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_chialisp_sort_program(): + diag_run_clvm(test_sort_program, Program.to([]), 'test_sort.sym') + +def test_permutations_n(): + for i in range(3,6): + do_test_permutations_of_size_n(i) + +def test_chialisp_permutations_program(): + diag_run_clvm(test_permutations_program, Program.to([3, 5]), 'test_permutations.sym') + +def test_smoke_sort(): + for length in range(7): # 0-7 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + sort_args = Program.to([orig_list]) + sorted_list = Program.to(sorted(orig_list)) + sort_res = sort_program.run(sort_args) + assert sort_res == sorted_list + +if __name__ == '__main__': + test_smoke_sort() diff --git a/resources/tests/game-referee-in-cl21/test_permutations.clsp b/resources/tests/game-referee-in-cl21/test_permutations.clsp new file mode 100644 index 000000000..d5b6d125f --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_permutations.clsp @@ -0,0 +1,63 @@ +(mod (M N) + (include *standard-cl-21*) + (include prepend.clinc) + (include reverse.clinc) + (include map.clinc) + (include len.clinc) + (include range.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + (include all-in-list.clinc) + (include print.clinc) + + (defun ! (x) + (if x + (* x (! (- x 1))) + 1 + ) + ) + (defun no_repeats_inner ((first . remainder)) + (if remainder + (if (deep= first (f remainder)) + 0 + (no_repeats_inner remainder) + ) + 1 + ) + ) + (defun no_repeats (mylist) + (if mylist + (no_repeats_inner (sort (lambda (a b) (= (deep_compare a b) -1)) mylist)) + 1 + ) + ) + (assert + ;; Is permutations expected to collapse equal alternatives when two of + ;; the items to shuffle are equal? + (= (* (! M) 4) (len (permutations (c 0 (range M))))) + (busy + (lambda (listlen) + (assign + mylist (range listlen) + permed (permutations mylist) + (assert + (= (len permed) (! listlen)) + ;; ensure we didn't produce any permutations that have + ;; repeated elements in them, which would indicate that + ;; the permutation function misbehaved + (all-in-list (map (lambda (L) (no_repeats L)) permed)) + (no_repeats permed) + ) + ) + ) + (reverse (range N)) + 1 + ) + (deep= (permutations 0) (q ())) + 0 + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex new file mode 100644 index 000000000..9758d6fd7 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ffff03ffff09ffff12ffff02ff66ffff04ff02ffff04ff05ff80808080ffff010480ffff02ff48ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff04ffff0180ffff02ff58ffff04ff02ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff5affff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200fe80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff50ffff04ff02ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff80808080ffff04ffff0101ff808080808080ffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff0180ff80808080ffff04ffff01ff8080ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff04ffff01ffffffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff40ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff02ff60ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff60ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff70ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffffff02ffff03ff05ffff01ff02ffff01ff10ffff0101ffff02ff48ffff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff68ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffff02ff68ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff05ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffffffff02ff78ffff04ff02ffff04ff05ffff01ff80ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff44ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff6cffff04ff02ffff04ff03ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff54ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff7cffff04ff02ffff04ffff06ff0180ffff04ffff02ff5cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffffffff09ffff02ff5cffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff4affff04ff02ffff04ffff02ff40ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff62ffff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffff02ffff03ff05ffff01ff02ffff01ff02ff62ffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff6affff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff6affff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff5affff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff04ffff04ffff0101ffff05ff058080ffff02ff7affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffffff02ffff04ffff0122ffff02ff7affff04ff02ffff04ff05ff8080808080ff8080ff02ffff03ff05ffff01ff02ffff01ff12ff05ffff02ff66ffff04ff02ffff04ffff11ff05ffff010180ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffff02ffff03ff0dffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ff09ffff04ffff05ff0d80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff56ffff04ff02ffff04ff0dff80808080ff018080ff0180ff0180ffff01ff02ffff01ff0101ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff56ffff04ff02ffff04ffff02ff74ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ff80808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffffff09ffff02ff5cffff04ff02ffff04ff0bffff04ff17ff8080808080ffff0181ff80ff02ff5effff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ffff09ffff02ff48ffff04ff02ffff04ff0bff80808080ffff02ff66ffff04ff02ffff04ff29ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff46ffff04ff02ffff04ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200be80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff0bffff04ffff0180ff808080808080ff80808080ffff01ff02ffff01ff02ff76ffff04ff02ffff04ff0bff80808080ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff02ff76ffff04ff02ffff04ff0bff80808080ff02ff6effff04ff02ffff04ffff04ff80ffff04ff0bff808080ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_permutations.sym b/resources/tests/game-referee-in-cl21/test_permutations.sym new file mode 100644 index 000000000..d28b3e38a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_permutations.sym @@ -0,0 +1 @@ +{"42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f_left_env": "1", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522": "no_repeats_inner", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8_left_env": "1", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53_arguments": "(reversed rest)", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de": "deep_compare", "93ebb2292470d39d1a556d1294e5da2de17b55aa7d6b591cb885754273777746": "permutations_inner", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79": "last_inner", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de_arguments": "(a b)", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff_left_env": "1", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7_left_env": "1", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682": "no_repeats", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202_arguments": "(@ everything (rest aggl aggr))", "93ebb2292470d39d1a556d1294e5da2de17b55aa7d6b591cb885754273777746_left_env": "1", "42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f_arguments": "(myless A B agg)", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7": "busy", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238_arguments": "((() listlen) mylist)", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_permutations.clsp", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c": "range_inner", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53": "reverse_inner", "93ebb2292470d39d1a556d1294e5da2de17b55aa7d6b591cb885754273777746_arguments": "(pre post agg)", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e_arguments": "(L)", "9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793": "lambda_$_305", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_304", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977_arguments": "(vals)", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d_arguments": "(((() listlen) mylist) permed)", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8_arguments": "(F L R)", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08_arguments": "(myless a b)", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c": "letbinding_$_300", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565": "sort", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68_left_env": "1", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047": "deep=", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706": "lambda_$_298", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565_arguments": "(myless mylist)", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87": "prepend", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9_left_env": "1", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d": "letbinding_$_306", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d_left_env": "1", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682_arguments": "(mylist)", "6eb64b0043f60821f8c78916633c5d028164853a0ef677c0b35666673f4163ba_left_env": "1", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a_left_env": "1", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2": "!", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a": "len", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977": "reverse", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202_left_env": "1", "6eb64b0043f60821f8c78916633c5d028164853a0ef677c0b35666673f4163ba_arguments": "((pre_$_275 post_$_276 agg_$_277) myatom newrest)", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860": "letbinding_$_301", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61": "permutations", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe": "range", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860_arguments": "(((myless_$_257 mylist_$_258) (a b)) sa sb)", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom) x)", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9_arguments": "(L)", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e_arguments": "(mylist)", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047_left_env": "1", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2_left_env": "1", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68": "lambda_$_307", "9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793_left_env": "1", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706_arguments": "(() listlen)", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8": "map-with-rest", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08": "merge", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238": "letbinding_$_299", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e_left_env": "1", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87_arguments": "(a b)", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c_arguments": "(next final)", "__chia__main_arguments": "(M N)", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e": "split", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a_arguments": "(L)", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe_arguments": "(i)", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c_left_env": "1", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522_left_env": "1", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238_left_env": "1", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61_left_env": "1", "6eb64b0043f60821f8c78916633c5d028164853a0ef677c0b35666673f4163ba": "letbinding_$_303", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08_left_env": "1", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2_arguments": "(x)", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87_left_env": "1", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9": "enquote-rest", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565_left_env": "1", "9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793_arguments": "(() a b)", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202": "split_inner", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522_arguments": "((first . remainder))", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977_left_env": "1", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79_arguments": "((next . remainder))", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68_arguments": "(() L)", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706_left_env": "1", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c_arguments": "((myless_$_257 mylist_$_258) (a b))", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e": "all-in-list", "42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f": "merge_inner", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff": "letbinding_$_302", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047_arguments": "(a b)", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79_left_env": "1", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7_arguments": "(myfunc mylist returnval)", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff_arguments": "((a_$_261 b_$_262) inner_result)", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61_arguments": "(vals)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_prepend.clsp b/resources/tests/game-referee-in-cl21/test_prepend.clsp new file mode 100644 index 000000000..9f0d45819 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_prepend.clsp @@ -0,0 +1,5 @@ +(mod (X Y) + (include *standard-cl-21*) + (include prepend.clinc) + (prepend X Y) + ) diff --git a/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex new file mode 100644 index 000000000..47dd7f1f1 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff02ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_prepend.sym b/resources/tests/game-referee-in-cl21/test_prepend.sym new file mode 100644 index 000000000..368cc453d --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_prepend.sym @@ -0,0 +1 @@ +{"source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_prepend.clsp", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987_left_env": "1", "__chia__main_arguments": "(X Y)", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987": "prepend", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987_arguments": "(a b)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_range.clsp b/resources/tests/game-referee-in-cl21/test_range.clsp new file mode 100644 index 000000000..a7dc5edd9 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_range.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-21*) + (include range.clinc) + + (range X) + ) diff --git a/resources/tests/game-referee-in-cl21/test_range.clvm.hex b/resources/tests/game-referee-in-cl21/test_range.clvm.hex new file mode 100644 index 000000000..628a68fe6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_range.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff04ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_range.sym b/resources/tests/game-referee-in-cl21/test_range.sym new file mode 100644 index 000000000..fabe9f400 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_range.sym @@ -0,0 +1 @@ +{"0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_left_env": "1", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556": "range_inner", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_range.clsp", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_arguments": "(i)", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556_left_env": "1", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556_arguments": "(next final)", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a": "range", "__chia__main_arguments": "(X)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_reverse.clsp b/resources/tests/game-referee-in-cl21/test_reverse.clsp new file mode 100644 index 000000000..b1d843648 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_reverse.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-21*) + (include reverse.clinc) + + (reverse X) + ) diff --git a/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex new file mode 100644 index 000000000..492966787 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ffff01ff02ff04ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_reverse.sym b/resources/tests/game-referee-in-cl21/test_reverse.sym new file mode 100644 index 000000000..e573ba66a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_reverse.sym @@ -0,0 +1 @@ +{"0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_arguments": "(vals)", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01_left_env": "1", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_reverse.clsp", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_left_env": "1", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01": "reverse_inner", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a": "reverse", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01_arguments": "(reversed rest)", "__chia__main_arguments": "(X)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/test_sort.clsp b/resources/tests/game-referee-in-cl21/test_sort.clsp new file mode 100644 index 000000000..8185024d0 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_sort.clsp @@ -0,0 +1,37 @@ + +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include range.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + + (defun try_list (mylist newlist) + (assert (deep= (print "sorted" (sort (lambda (A B) (deep< A B)) newlist)) mylist) 0) + ) + + (defun try_permuted_list (mylist) + (busy (lambda ((& mylist) newlist) (try_list mylist newlist)) + (print "sort all these" (permutations (print "mylist" mylist))) + 0 + ) + ) + (last + (try_list 0 0) + (try_list (range 15) (range 15)) + (try_list (range 15) (reverse (range 15))) + (try_permuted_list (list -1 -1 0 0 2)) + (busy (lambda (i) (try_permuted_list (print "sortme" (range i)))) + (range 4) + 0 + ) + 1 + ) +) diff --git a/resources/tests/game-referee-in-cl21/test_sort.clvm.hex b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex new file mode 100644 index 000000000..4cf09e661 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff4affff04ff02ffff04ffff0104ff80808080ffff04ffff0180ff808080808080ffff04ffff02ff6effff04ff02ffff04ffff04ffff0181ffffff04ffff0181ffffff04ffff0180ffff04ffff0180ffff04ffff0102ffff01808080808080ff80808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff7cffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff0180ffff04ffff0180ff8080808080ffff04ffff0101ffff0180808080808080ff80808080ffff04ffff01ffffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff50ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff50ffff04ff02ffff04ff05ffff01ff80ff8080808080ffffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0180ffff04ffff02ff70ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff24ffff04ff02ffff04ff03ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffffff02ff68ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff74ffff04ff02ffff04ffff06ff0180ffff04ffff02ff54ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ffff02ffff03ff0bffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff5cffff04ff02ffff04ff80ffff04ff05ff8080808080ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff22ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff52ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff72ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffffff02ff72ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff5affff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff52ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7a80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff46ffff04ff02ffff04ffff02ff22ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff6affff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffffff02ffff03ff05ffff01ff02ffff01ff02ff6affff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff66ffff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff56ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff02ff6cffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746564ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff0bff8080808080ff8080808080ffff04ff05ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffffff02ff4cffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff5e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff05ff808080ffff01ff01808080ff80808080ffff04ffff02ff20ffff04ff02ffff04ffff018e736f727420616c6c207468657365ffff04ffff02ff46ffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff01866d796c697374ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff808080808080ffff02ff76ffff04ff02ffff04ff09ffff04ff0bff8080808080ff02ff6effff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746d65ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ff80808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_sort.sym b/resources/tests/game-referee-in-cl21/test_sort.sym new file mode 100644 index 000000000..6bea76365 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_sort.sym @@ -0,0 +1 @@ +{"e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c": "map-with-rest", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3": "reverse", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f": "reverse_inner", "997e0518ff66cefb408f6f6b874f0395ae1399f73650dc57f45d6f4eb79daccc_left_env": "1", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329_arguments": "(@ everything (rest aggl aggr))", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219_left_env": "1", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5_arguments": "((next . remainder))", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5_left_env": "1", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b": "range_inner", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b_arguments": "((myless_$_144 mylist_$_145) (a b))", "e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c_arguments": "(F L R)", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499": "try_permuted_list", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb_left_env": "1", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499_arguments": "(mylist)", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d_left_env": "1", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5": "sort", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7_arguments": "(a b)", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872": "letbinding_$_197", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5_left_env": "1", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2": "letbinding_$_196", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_arguments": "(R P)", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2_arguments": "(((myless_$_144 mylist_$_145) (a b)) sa sb)", "d5c36bb1c58c5974069b15c197ca27352476f19db460fb8cfa79fc1f35f55b13_left_env": "1", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560": "lambda_$_201", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d": "merge_inner", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141": "split", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22": "merge", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d_arguments": "(a b)", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f_arguments": "(reversed rest)", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3_left_env": "1", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141_arguments": "(mylist)", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560_arguments": "((mylist_$_193) newlist)", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7": "lambda_$_194", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d_arguments": "(a b)", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_199", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329_left_env": "1", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3_arguments": "(vals)", "e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c_left_env": "1", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b_left_env": "1", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b_arguments": "(next final)", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d": "deep_compare", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d_left_env": "1", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219_arguments": "(mylist newlist)", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560_left_env": "1", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5_left_env": "1", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499_left_env": "1", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d_left_env": "1", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb": "busy", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom) x)", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679": "prepend", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872_left_env": "1", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7_arguments": "(() i)", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e": "print", "997e0518ff66cefb408f6f6b874f0395ae1399f73650dc57f45d6f4eb79daccc_arguments": "(pre post agg)", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f_left_env": "1", "d5c36bb1c58c5974069b15c197ca27352476f19db460fb8cfa79fc1f35f55b13": "letbinding_$_198", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b_left_env": "1", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329": "split_inner", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b_arguments": "(i)", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141_left_env": "1", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24": "permutations", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219": "try_list", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5_arguments": "(() A B)", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7_left_env": "1", "997e0518ff66cefb408f6f6b874f0395ae1399f73650dc57f45d6f4eb79daccc": "permutations_inner", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5": "last_inner", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22_left_env": "1", "d5c36bb1c58c5974069b15c197ca27352476f19db460fb8cfa79fc1f35f55b13_arguments": "((pre_$_176 post_$_177 agg_$_178) myatom newrest)", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b_left_env": "1", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7_left_env": "1", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5_arguments": "(myless mylist)", "__chia__main_arguments": "()", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24_arguments": "(vals)", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d_arguments": "(myless A B agg)", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872_arguments": "((a_$_148 b_$_149) inner_result)", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7": "deep=", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22_arguments": "(myless a b)", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679_arguments": "(a b)", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d": "deep<", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_left_env": "1", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-in-cl21/test_sort.clsp", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5": "lambda_$_200", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b": "letbinding_$_195", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb_arguments": "(myfunc mylist returnval)", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b": "range", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl21/testnoncegame.py b/resources/tests/game-referee-in-cl21/testnoncegame.py new file mode 100644 index 000000000..3b4cd2c2a --- /dev/null +++ b/resources/tests/game-referee-in-cl21/testnoncegame.py @@ -0,0 +1,33 @@ +import hashlib + +from hsms.streamables.program import Program + +from clvm.EvalError import EvalError + +noncegame = Program.from_bytes(bytes.fromhex(open("noncegame.clvm.hex").read())) +noncehash = noncegame.tree_hash() + +def drun(prog: Program, args: Program): + try: + return prog.run(args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(args)}") + raise + +def testnonce(startnonce, maxnonce): + for i in range(startnonce, maxnonce): + mygame = noncegame.curry(i, noncehash) + good_parameters = [i*2, noncegame.curry(i+1, noncehash).tree_hash(), 1, (i*4, b'g')] + bad_parameters = [i*3, noncegame.curry(i+2, noncehash).tree_hash(), 2, (i*5, b'g')] + assert drun(mygame, good_parameters) == b'g' + for j in range(len(good_parameters)): + try: + p = list(good_parameters) + p[j] = bad_parameters[j] + mygame.run(p) + assert False + except EvalError as ee: + pass + +if __name__ == '__main__': + testnonce(3, 7) diff --git a/resources/tests/game-referee-in-cl21/testreferee.py b/resources/tests/game-referee-in-cl21/testreferee.py new file mode 100644 index 000000000..01eb53643 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/testreferee.py @@ -0,0 +1,479 @@ +import pytest +from hashlib import sha256 +from contextlib import asynccontextmanager +from chia.clvm.spend_sim import SimClient, SpendSim +from pathlib import Path +from clvm.casts import int_to_bytes, int_from_bytes + +from hsms.streamables.program import Program +from clvm_tools_rs import compile_clvm +from clvm_tools.binutils import disassemble + +from clvm.EvalError import EvalError +from chia.types.mempool_inclusion_status import MempoolInclusionStatus +from chia.util.errors import Err +from dataclasses import dataclass +from typing import Any +from chia_rs import Coin +from chia.types.spend_bundle import SpendBundle +from chia.types.coin_spend import CoinSpend +from blspy import G2Element + +from steprun import diag_run_clvm, compile_module_with_symbols + +compile_module_with_symbols(['.'],'referee.clsp') +referee = Program.from_bytes(bytes.fromhex(open("referee.clvm.hex").read())) +refhash = referee.tree_hash() +compile_module_with_symbols(['.'],'referee_accuse.clsp') +referee_accuse = Program.from_bytes(bytes.fromhex(open("referee_accuse.clvm.hex").read())) +refaccusehash = referee.tree_hash() +compile_clvm('rockpaperscissorsa.clsp', 'rockpaperscissorsa.clvm.hex', ['.']) +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +compile_clvm('rockpaperscissorsb.clsp', 'rockpaperscissorsb.clvm.hex', ['.']) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +compile_clvm('rockpaperscissorsc.clsp', 'rockpaperscissorsc.clvm.hex', ['.']) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +compile_clvm('rockpaperscissorsd.clsp', 'rockpaperscissorsd.clvm.hex', ['.']) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + +move = 0 +accuse = 1 +timeout = 2 + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha(blob:bytes) -> bytes: + return sha256(blob).digest() + +@pytest.fixture(scope="function") +@asynccontextmanager +async def setup_sim() : + sim = await SpendSim.create(db_path=Path("file:db_test?mode=memory&cache=shared")) + sim_client = SimClient(sim) + await sim.farm_block() + + try: + yield sim, sim_client + finally: + await sim.close() + +def bootstrap_referee(parent_coin_id, initial_validation_program_hash, initial_split, + amount, timeout, max_move_size, mover_puzzle, waiter_puzzle): + """ + returns referee_wrap + """ + puzzle_hash = referee.curry( + [initial_validation_program_hash, 0, initial_split, amount, timeout, max_move_size, mover_puzzle.tree_hash(), + waiter_puzzle.tree_hash(), referee.tree_hash()]).tree_hash() + coin = Coin(parent_coin_id, puzzle_hash, amount) + return RefereeWrap(coin, bytes(32), bytes(32), bytes(32), + initial_validation_program_hash, 0, initial_split, timeout, max_move_size, + mover_puzzle, waiter_puzzle) + +@dataclass +class RefereeWrap: + coin: Any + grandparent_id: Any + parent_validation_program_hash: Any + parent_everything_else_hash: Any + validation_program_hash: Any + move: Any + split: Any + timeout: Any + max_move_size: Any + mover_puzzle: Any + waiter_puzzle: Any + + def curried_parameters_for_our_puzzle(self, purpose, for_self, move_to_make, split, validation_program_hash): + result = Program.to([ + validation_program_hash, + move_to_make, + split, + self.coin.amount, + self.timeout, + self.max_move_size, + self.mover_puzzle.tree_hash() if for_self else self.waiter_puzzle.tree_hash(), + self.waiter_puzzle.tree_hash() if for_self else self.mover_puzzle.tree_hash(), + refhash + ]) + print(f'for {purpose} curried_parameters_for_our_puzzle is {result}') + return result + + def get_puzzle(self): + return referee.curry(self.curried_parameters_for_our_puzzle( + "GET_PUZZLE", + True, + self.move, + self.split, + self.validation_program_hash + )) + + def SpendMove(self, password, move_to_make, split, validation_program_hash): + """ + returns (solution, new RefereeWrap) + """ + print(f"MOVE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"MOVE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + curried_parameters = self.curried_parameters_for_our_puzzle( + "SPEND_MOVE", + False, + move_to_make, + split, + validation_program_hash + ) + print(f"MOVE referee curried parameters {curried_parameters}") + new_puzzle_hash = referee.curry(curried_parameters).tree_hash() + print(f"MOVE new puzzle hash {Program.to(new_puzzle_hash)}") + solution = Program.to([move, move_to_make, split, validation_program_hash, self.mover_puzzle, + [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + everything_else_hash = Program.to([self.move, self.split, self.coin.amount, self.timeout, + self.max_move_size, self.mover_puzzle.tree_hash(), self.waiter_puzzle.tree_hash(), + referee.tree_hash()]).tree_hash() + return (solution, RefereeWrap(coin, self.coin.parent_coin_info, self.validation_program_hash, everything_else_hash, + validation_program_hash, move_to_make, split, self.timeout, self.max_move_size, + self.waiter_puzzle, self.mover_puzzle)) + + def SpendAccuse(self, password): + """ + returns (solution, RefereeAccuse) + """ + print(f"ACCUSE starting with puzzle hash {Program.to(self.get_puzzle().tree_hash())}") + print(f"ACCUSE parent_id {Program.to(self.coin.parent_coin_info)}") + print(f"ACCUSE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"ACCUSE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + new_puzzle_hash = referee_accuse.curry([ + self.parent_validation_program_hash, + self.validation_program_hash, + self.move, + self.split, + self.coin.amount, + self.timeout, + self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash() + ]).tree_hash() + solution = Program.to([accuse, self.grandparent_id, self.parent_validation_program_hash, + self.parent_everything_else_hash, self.mover_puzzle, [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + return (solution, RefereeAccuseWrap(coin, self.parent_validation_program_hash, self.validation_program_hash, + self.move, self.split, self.timeout, self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash())) + + def SpendTimeout(self): + """ + returns (solution, movercoinid, waitercoinid) + """ + movercoinid = Coin(self.coin.name(), self.mover_puzzle.tree_hash(), self.split).name() + waitercoinid = Coin(self.coin.name(), self.waiter_puzzle.tree_hash(), + self.coin.amount - self.split).name() + return (Program.to((timeout, 0)), movercoinid, waitercoinid) + +@dataclass +class RefereeAccuseWrap: + coin: Any + old_validation_puzzle_hash: Any + new_validation_puzzle_hash: Any + move: Any + split: Any + timeout: Any + accused_puzzle_hash: Any + accuser_puzzle_hash: Any + + def get_puzzle(self): + return referee_accuse.curry([self.old_validation_puzzle_hash, self.new_validation_puzzle_hash, + self.move, self.split, self.coin.amount, self.timeout, self.accused_puzzle_hash, + self.accuser_puzzle_hash]) + + def SpendTimeout(self): + """ + returns (solution, coinid) + """ + coin = Coin(self.coin.name(), self.accuser_puzzle_hash, self.coin.amount) + return (Program.to(0), coin.name()) + + def SpendDefend(self, validation_program_reveal, validation_program_solution): + """ + returns (solution, coinid) + """ + solution = Program.to([validation_program_reveal, validation_program_solution]) + coin = Coin(self.coin.name(), self.accused_puzzle_hash, self.coin.amount) + return (solution, coin.name()) + +@pytest.mark.asyncio +@pytest.mark.parametrize('amove', [0, 1, 2]) +@pytest.mark.parametrize('bmove', [0, 1, 2]) +async def test_rps(amove, bmove, setup_sim): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = int_to_bytes(60 + amove) + alice_image = sha(alice_preimage) + bob_preimage = int_to_bytes(60 + bmove) + bob_image = sha(bob_preimage) + alice_move = int_to_bytes(amove) + nil = Program.to(0) + + # (mod (password . conditions) (if (= password 'alice') conditions (x))) + alice_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0185616c69636580ffff0103ffff01ff088080ff0180')) + alice_puzzle_hash = alice_puzzle.tree_hash() + # (mod (password . conditions) (if (= password 'bob') conditions (x))) + bob_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0183626f6280ffff0103ffff01ff088080ff0180')) + bob_puzzle_hash = bob_puzzle.tree_hash() + + async with setup_sim as (sym, client): + acs = Program.to(1) + acs_hash = acs.tree_hash() + await sym.farm_block(acs_hash) + mycoin = (await client.get_coin_records_by_puzzle_hashes([acs_hash], include_spent_coins = False))[0].coin + # make a coin for a game + referee = bootstrap_referee(mycoin.name(), MOD_A.tree_hash(), 2, total, 1000, 50, alice_puzzle, bob_puzzle) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(mycoin, acs, Program.to([[51, referee.coin.puzzle_hash, + referee.coin.amount]]))], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse Bob of cheating (negative test, should fail) + solution, accuse = referee.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_MY_PARENT_ID_FAILED + # timeout too early fail + solution, alice_reward_id, bob_reward_id = referee.SpendTimeout() + spend = SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # timeout succeeds + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == 2 + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == total - 2 + await sym.rewind(savepoint) + # Alice makes an illegally large move, fails + solution, ref2 = referee.SpendMove('alice', bytes(100), 0, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with negative split, fails + solution, ref2 = referee.SpendMove('alice', 'abc', -1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with split greater than amount, fails + solution, ref2 = referee.SpendMove('alice', 'abc', referee.coin.amount + 1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice move 1 commit to image + bpuz = MOD_B.curry(alice_image) + solution, ref2 = referee.SpendMove('alice', alice_image, 0, bpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuse Alice of cheating + solution, accuse = ref2.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint2 = sym.block_height + # Alice accusation defend, gets everything + solution, reward_id = accuse.SpendDefend(MOD_A, nil) + print(solution) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == alice_puzzle_hash + await sym.rewind(savepoint2) + # accusation timeout too early fail + solution, reward_id = accuse.SpendTimeout() + spend = SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # accusation timeout succeed, Bob gets everything + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Bob move 2 commit to image + cpuz = MOD_C.curry([alice_image, bob_image]) + solution, ref3 = ref2.SpendMove('bob', bob_image, 0, cpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse + solution, accuse = ref3.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(bpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin = (await client.get_coin_records_by_names([reward_id], include_spent_coins = + False))[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Alice reveals wrong preimage + alice_bad_preimage = int_to_bytes(61 + amove) + dpuz = MOD_D.curry([(amove + 1) % 3, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends, fails + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Alice move 3 reveal preimage + dpuz = MOD_D.curry([alice_move, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.rewind(savepoint) + # Bob move 4 reveal wrong preimage + bob_bad_preimage = int_to_bytes(121 + amove) + solution, ref5 = ref4.SpendMove('bob', bob_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Bob attempts defense with wrong validation program, fails + solution, reward_id = accuse.SpendDefend(acs, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + if amove == bmove: + # Bob move 4 gives wrong split + solution, ref5 = ref4.SpendMove('bob', bob_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Bob move 4 reveal preimage + solution, ref5 = ref4.SpendMove('bob', bob_preimage, alice_final, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice attempts move, fails + solution, ref6 = ref5.SpendMove('alice', nil, 0, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # timeout, split correct + sym.pass_time(2000) + await sym.farm_block() + solution, alice_reward_id, bob_reward_id = ref5.SpendTimeout() + spend = SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + if alice_final != 0: + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == alice_final + else: + assert len(await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False)) == 0 + if alice_final != ref5.coin.amount: + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == ref5.coin.amount - alice_final + else: + assert len(await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False)) == 0 + await sym.rewind(savepoint) + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert (status, err) == (MempoolInclusionStatus.SUCCESS, None) diff --git a/resources/tests/game-referee-in-cl21/testrockpaperscissors.py b/resources/tests/game-referee-in-cl21/testrockpaperscissors.py new file mode 100644 index 000000000..ed45dbccc --- /dev/null +++ b/resources/tests/game-referee-in-cl21/testrockpaperscissors.py @@ -0,0 +1,48 @@ +import hashlib + +from hsms.streamables.program import Program +from hsms.puzzles.load_clvm import load_clvm + +from clvm.EvalError import EvalError + + +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha256(blob:bytes) -> bytes: + return hashlib.sha256(blob).digest() + +def testrps(amove, bmove): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = Program.to(60 + amove) + bob_preimage = Program.to(60 + bmove) + alice_image = sha256(alice_preimage.atom) + bob_image = sha256(bob_preimage.atom) + alice_move = Program.to(amove) + + cd = MOD_D.curry(alice_move, bob_image) + assert cd.run([total, bob_preimage, b'', alice_final, b'j']).atom == b'j' + cc = MOD_C.curry(alice_image, bob_image) + assert cc.run([total, alice_preimage, cd.tree_hash(), 0, b'j']).atom == b'j' + cb = MOD_B.curry(alice_image) + assert cb.run([total, bob_image, cc.tree_hash(), 0, b'j']).atom == b'j' + assert MOD_A.run([total, alice_image, cb.tree_hash(), 0, b'j']).atom == b'j' + +def testall(): + for i in range(3): + for j in range(3): + testrps(i, j) + +if __name__ == '__main__': + testall() diff --git a/resources/tests/lib/__init__.py b/resources/tests/lib/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/resources/tests/lib/all-in-list.clinc b/resources/tests/lib/all-in-list.clinc new file mode 100644 index 000000000..1db5f26ad --- /dev/null +++ b/resources/tests/lib/all-in-list.clinc @@ -0,0 +1,12 @@ +( + (defun enquote-rest (L) + (if L + (c (c 1 (f L)) (enquote-rest (r L))) + () + ) + ) + + (defun all-in-list (L) + (a (c 34 (enquote-rest L)) ()) + ) +) diff --git a/resources/tests/lib/assert.clinc b/resources/tests/lib/assert.clinc new file mode 100644 index 000000000..c9f212394 --- /dev/null +++ b/resources/tests/lib/assert.clinc @@ -0,0 +1,8 @@ +( + (defmacro assert items + (if (r items) + (list if (f items) (c assert (r items)) (q . (x))) + (f items) + ) + ) +) diff --git a/resources/tests/lib/busy.clinc b/resources/tests/lib/busy.clinc new file mode 100644 index 000000000..e534d2125 --- /dev/null +++ b/resources/tests/lib/busy.clinc @@ -0,0 +1,11 @@ +( + (defun busy (myfunc mylist returnval) + (if mylist + (last + (a myfunc (list (f mylist))) + (busy myfunc (r mylist) returnval) + ) + returnval + ) + ) +) diff --git a/resources/tests/lib/condition_codes.clinc b/resources/tests/lib/condition_codes.clinc new file mode 100644 index 000000000..45f3265da --- /dev/null +++ b/resources/tests/lib/condition_codes.clinc @@ -0,0 +1,41 @@ +; See chia/types/condition_opcodes.py + +( + (defconstant AGG_SIG_UNSAFE 49) + (defconstant AGG_SIG_ME 50) + + ; the conditions below reserve coin amounts and have to be accounted for in output totals + + (defconstant CREATE_COIN 51) + (defconstant RESERVE_FEE 52) + + ; the conditions below deal with announcements, for inter-coin communication + + ; coin announcements + (defconstant CREATE_COIN_ANNOUNCEMENT 60) + (defconstant ASSERT_COIN_ANNOUNCEMENT 61) + + ; puzzle announcements + (defconstant CREATE_PUZZLE_ANNOUNCEMENT 62) + (defconstant ASSERT_PUZZLE_ANNOUNCEMENT 63) + + ; the conditions below let coins inquire about themselves + + (defconstant ASSERT_MY_COIN_ID 70) + (defconstant ASSERT_MY_PARENT_ID 71) + (defconstant ASSERT_MY_PUZZLEHASH 72) + (defconstant ASSERT_MY_AMOUNT 73) + + ; the conditions below ensure that we're "far enough" in the future + + ; wall-clock time + (defconstant ASSERT_SECONDS_RELATIVE 80) + (defconstant ASSERT_SECONDS_ABSOLUTE 81) + + ; block index + (defconstant ASSERT_HEIGHT_RELATIVE 82) + (defconstant ASSERT_HEIGHT_ABSOLUTE 83) + + ; A condition that is always true and always ignore all arguments + (defconstant REMARK 1) +) diff --git a/resources/tests/lib/curry-and-treehash.clinc b/resources/tests/lib/curry-and-treehash.clinc new file mode 100644 index 000000000..6a63e9364 --- /dev/null +++ b/resources/tests/lib/curry-and-treehash.clinc @@ -0,0 +1,92 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `shatree`. + + (defconstant ONE 1) + (defconstant TWO 2) + (defconstant A_KW #a) + (defconstant Q_KW #q) + (defconstant C_KW #c) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 TWO (sha256 ONE C_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) parameter-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash`, updating `environment-hash` + ;; along the way. + + (defun build-curry-list (reversed-curry-parameter-hashes environment-hash) + (if reversed-curry-parameter-hashes + (build-curry-list (r reversed-curry-parameter-hashes) + (update-hash-for-parameter-hash (f reversed-curry-parameter-hashes) environment-hash)) + environment-hash + ) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `function-hash` of a function tree F + ;; return the tree hash of the tree corresponding to + ;; `(a (q . F) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . F) E)` = `(a . ((q . F) . (E . 0)))` + + (defun-inline tree-hash-of-apply (function-hash environment-hash) + (sha256 TWO (sha256 ONE A_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) function-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; function-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; reversed-curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; Note that this must be applied in REVERSED order. This may seem strange, but it greatly simplifies + ;; the underlying code, since we calculate the tree hash from the bottom nodes up, and the last + ;; parameters curried must have their hashes calculated first. + ;; + ;; we return the hash of the curried expression + ;; (a (q . function-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the actual curried program. + + (defun puzzle-hash-of-curried-function (function-hash . reversed-curry-parameter-hashes) + (tree-hash-of-apply function-hash + (build-curry-list reversed-curry-parameter-hashes (sha256 ONE ONE))) + ) + + (defconstant b32 32) + + (defun-inline size_b32 (var) + (= (strlen var) b32) + ) + + (defun calculate_coin_id (parent puzzlehash amount) + (if (all (size_b32 parent) (size_b32 puzzlehash) (> amount -1)) + (sha256 parent puzzlehash amount) + (x) + ) + ) + + ; takes a lisp tree and returns the hash of it + (defun shatree (TREE) + (if (l TREE) + (sha256 2 (shatree (f TREE)) (shatree (r TREE))) + (sha256 1 TREE))) + +) diff --git a/resources/tests/lib/curry.clinc b/resources/tests/lib/curry.clinc new file mode 100644 index 000000000..81a1ec3a6 --- /dev/null +++ b/resources/tests/lib/curry.clinc @@ -0,0 +1,104 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `shatree`. + + (defconstant TWO 2) + (defconstant constant-tree ( + (0x4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a . ; = `(sha256 1)` + 0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2) . ; = `(sha256 1 1)` = `(sha256 1 #q)` + (0x02a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222 . ; = `(concat 2 (sha256 1 #a))` + 0x02a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5) ; = `(concat 2 (sha256 1 #c))` + ) + ) + + ; I looked into calculating the values of `constant-tree` because it's pretty easy to code-golf + ; out an implementation that produces the values cheaper than just inlining them. The problem is, + ; when do we calculate them? If there were a way to calculate it "before main" and include it in + ; the globally-accessible constant table, we could do that. But we can't which means to be optimal, + ; client code should call the "build table" code once, then pass it around to anyone that wants to + ; call `curry` or `curry2`. This is pretty intrusive, so for now we'll just use the existing + ; global constant infrastructure, and include it as a fixed table so the tree of four values will + ; appear in all code that includes this file, and it will compress better in generators. + + (defun-inline sha256_one _noargs (f (f constant-tree))) + (defun-inline sha256_one_one _noargs (r (f constant-tree))) + (defun-inline two_sha256_one_a_kw _noargs (f (r constant-tree))) + (defun-inline two_sha256_one_c_kw _noargs (r (r constant-tree))) + + ;; this returns the sha256 tree hash of expression F = `((q . a1) a2)` + (defun hash-expression-F (a1 a2) + (sha256 TWO (sha256 TWO (sha256_one_one) a1) + (sha256 TWO a2 (sha256_one))) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 (two_sha256_one_c_kw) (hash-expression-F parameter-hash environment-hash)) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `mod-hash` of a mod M + ;; return the tree hash of the tree corresponding to + ;; `(a (q . M) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . M) E)` = `(a . ((q . M) . (E . 0)))` + + (defun-inline tree-hash-of-apply (mod-hash environment-hash) + (sha256 (two_sha256_one_a_kw) (hash-expression-F mod-hash environment-hash)) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash` + + (defun calculate-hash-of-curried-parameters (curry-parameter-hashes) + (if curry-parameter-hashes + (update-hash-for-parameter-hash (f curry-parameter-hashes) (calculate-hash-of-curried-parameters (r curry-parameter-hashes))) + (sha256_one_one) + ) + ) + + ;; mod-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; + ;; we return the hash of the curried expression + ;; (a (q . mod-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the acutal curried program. + + ;; inline functions that take varargs don't seem to work, so we can't inline `curry` + + (defun curry_hashes (mod-hash . curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) + + + ;; this is included for future compilers that handle it properly. If you get weird + ;; errors using this, it may be your tooling. Use `curry` above instead, or inline manually. + + (defun-inline curry_hashes_inline (mod-hash . curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) + + ;; `curry_mod_hashes_inline` takes exactly two parameters rather than varags, and it can be inlined + + (defun-inline curry_mod_hashes_inline (mod-hash curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) +) diff --git a/resources/tests/lib/deep_compare.clinc b/resources/tests/lib/deep_compare.clinc new file mode 100644 index 000000000..0a863ae33 --- /dev/null +++ b/resources/tests/lib/deep_compare.clinc @@ -0,0 +1,41 @@ + +( + (defun deep_compare (a b) + (if (l a) + (if (l b) + (assign-lambda inner_result (deep_compare (f a) (f b)) + (if inner_result + inner_result + (deep_compare (r a) (r b)) + ) + ) + 1 + ) + (if (l b) + -1 + (if (> a b) + 1 + (- 0 (> b a)) + ) + ) + ) + ) + (defun deep< (a b) + (= (deep_compare a b) -1) + ) + (defun deep> (a b) + (= (deep_compare a b) 1) + ) + (defun deep= (a b) + (= (deep_compare a b) 0) + ) + (defun deep<= (a b) + (not (deep> a b)) + ) + (defun deep>= (a b) + (not (deep< a b)) + ) + (defun deep!= (a b) + (not (deep= a b)) + ) +) diff --git a/resources/tests/lib/filtermap.clinc b/resources/tests/lib/filtermap.clinc new file mode 100644 index 000000000..59c827858 --- /dev/null +++ b/resources/tests/lib/filtermap.clinc @@ -0,0 +1,14 @@ + +( + (defun filtermap (process remaining init) + (if remaining + (assign next (a process (list (f remaining))) + (if next + (c next (filtermap process (r remaining) init)) + (filtermap process (r remaining) init) + ) + ) + init + ) + ) +) \ No newline at end of file diff --git a/resources/tests/lib/flatten.clinc b/resources/tests/lib/flatten.clinc new file mode 100644 index 000000000..ab3815abd --- /dev/null +++ b/resources/tests/lib/flatten.clinc @@ -0,0 +1,12 @@ +( + (defun flatten_list (everything) + (if + (not everything) 0 + (prepend (f everything) (flatten_list (r everything))) + ) + ) + (defun flatten everything + (flatten_list everything) + ) + +) \ No newline at end of file diff --git a/resources/tests/lib/last.clinc b/resources/tests/lib/last.clinc new file mode 100644 index 000000000..5a6ffd73e --- /dev/null +++ b/resources/tests/lib/last.clinc @@ -0,0 +1,39 @@ +( + (defun last_inner ((next . remainder)) + (if remainder + (last_inner remainder) + next + ) + ) + + (defmacro last ARGS + (defun snoc (L agg) + (if L + (if (r L) + (snoc (r L) (c (f L) agg)) + (c (f L) agg) + ) + (c () ()) + ) + ) + + (defun prefix (L P) + (if L + (c (f L) (prefix (r L) P)) + P + ) + ) + + (if ARGS + (if (r ARGS) + (assign + (final . rest) (snoc ARGS ()) + reversed (prefix rest (list final)) + (qq (last_inner (unquote (c list reversed)))) + ) + (qq (last_inner (unquote (f ARGS)))) + ) + (x "Last takes at least one argument") + ) + ) +) diff --git a/resources/tests/lib/len.clinc b/resources/tests/lib/len.clinc new file mode 100644 index 000000000..407c36694 --- /dev/null +++ b/resources/tests/lib/len.clinc @@ -0,0 +1,3 @@ +( + (defun len (L) (if L (+ 1 (len (r L))) 0)) +) diff --git a/resources/tests/lib/load_clvm.py b/resources/tests/lib/load_clvm.py new file mode 100644 index 000000000..a01f37fbc --- /dev/null +++ b/resources/tests/lib/load_clvm.py @@ -0,0 +1,168 @@ +from __future__ import annotations + +import importlib +import inspect +import os +import pathlib +import sys +import tempfile +from typing import List + +import pkg_resources +from clvm_tools_rs import compile_clvm as compile_clvm_rust + +from chia.types.blockchain_format.program import Program +from chia.types.blockchain_format.serialized_program import SerializedProgram +from chia.util.lock import Lockfile + +compile_clvm_py = None + +recompile_requested = ( + (os.environ.get("CHIA_DEV_COMPILE_CLVM_ON_IMPORT", "") != "") or ("pytest" in sys.modules) +) and os.environ.get("CHIA_DEV_COMPILE_CLVM_DISABLED", None) is None + + +def translate_path(p_): + p = str(p_) + if os.path.isdir(p): + return p + else: + module_object = importlib.import_module(p) + return os.path.dirname(inspect.getfile(module_object)) + + +# Handle optional use of python clvm_tools if available and requested +if "CLVM_TOOLS" in os.environ: + try: + from clvm_tools.clvmc import compile_clvm as compile_clvm_py_candidate + + compile_clvm_py = compile_clvm_py_candidate + finally: + pass + + +def compile_clvm_in_lock(full_path: pathlib.Path, output: pathlib.Path, search_paths: List[pathlib.Path]): + # Compile using rust (default) + + # Ensure path translation is done in the idiomatic way currently + # expected. It can use either a filesystem path or name a python + # module. + treated_include_paths = list(map(translate_path, search_paths)) + res = compile_clvm_rust(str(full_path), str(output), treated_include_paths) + + if "CLVM_TOOLS" in os.environ and os.environ["CLVM_TOOLS"] == "check" and compile_clvm_py is not None: + # Simple helper to read the compiled output + def sha256file(f): + import hashlib + + m = hashlib.sha256() + m.update(open(f).read().strip().encode("utf8")) + return m.hexdigest() + + orig = "%s.orig" % output + + compile_clvm_py(full_path, orig, search_paths=search_paths) + orig256 = sha256file(orig) + rs256 = sha256file(output) + + if orig256 != rs256: + print("Compiled original %s: %s vs rust %s\n" % (full_path, orig256, rs256)) + print("Aborting compilation due to mismatch with rust") + assert orig256 == rs256 + else: + print("Compilation match %s: %s\n" % (full_path, orig256)) + + return res + + +def compile_clvm(full_path: pathlib.Path, output: pathlib.Path, search_paths: List[pathlib.Path] = []): + with Lockfile.create(pathlib.Path(tempfile.gettempdir()) / "clvm_compile" / full_path.name): + compile_clvm_in_lock(full_path, output, search_paths) + + +def load_serialized_clvm( + clvm_filename, package_or_requirement=__name__, include_standard_libraries: bool = False, recompile: bool = True +) -> SerializedProgram: + """ + This function takes a .clsp file in the given package and compiles it to a + .clsp.hex file if the .hex file is missing or older than the .clsp file, then + returns the contents of the .hex file as a `Program`. + + clvm_filename: file name + package_or_requirement: usually `__name__` if the clvm file is in the same package + """ + hex_filename = f"{clvm_filename}.hex" + + # Set the CHIA_DEV_COMPILE_CLVM_ON_IMPORT environment variable to anything except + # "" or "0" to trigger automatic recompilation of the Chialisp on load. + if recompile: + try: + if pkg_resources.resource_exists(package_or_requirement, clvm_filename): + # Establish whether the size is zero on entry + full_path = pathlib.Path(pkg_resources.resource_filename(package_or_requirement, clvm_filename)) + output = full_path.parent / hex_filename + if not output.exists() or os.stat(full_path).st_mtime > os.stat(output).st_mtime: + search_paths = [full_path.parent] + if include_standard_libraries: + # we can't get the dir, but we can get a file then get its parent. + chia_puzzles_path = pathlib.Path( + pkg_resources.resource_filename(__name__, "__init__.py") + ).parent + search_paths.append(chia_puzzles_path) + compile_clvm(full_path, output, search_paths=search_paths) + + except NotImplementedError: + # pyinstaller doesn't support `pkg_resources.resource_exists` + # so we just fall through to loading the hex clvm + pass + + clvm_hex = pkg_resources.resource_string(package_or_requirement, hex_filename).decode("utf8") + assert len(clvm_hex.strip()) != 0 + clvm_blob = bytes.fromhex(clvm_hex) + return SerializedProgram.from_bytes(clvm_blob) + + +def load_clvm( + clvm_filename, + package_or_requirement=__name__, + include_standard_libraries: bool = False, + recompile: bool = True, +) -> Program: + return Program.from_bytes( + bytes( + load_serialized_clvm( + clvm_filename, + package_or_requirement=package_or_requirement, + include_standard_libraries=include_standard_libraries, + recompile=recompile, + ) + ) + ) + + +def load_clvm_maybe_recompile( + clvm_filename, + package_or_requirement=__name__, + include_standard_libraries: bool = False, + recompile: bool = recompile_requested, +) -> Program: + return load_clvm( + clvm_filename=clvm_filename, + package_or_requirement=package_or_requirement, + include_standard_libraries=include_standard_libraries, + recompile=recompile, + ) + + +def load_serialized_clvm_maybe_recompile( + clvm_filename, + package_or_requirement=__name__, + include_standard_libraries: bool = False, + recompile: bool = recompile_requested, +) -> SerializedProgram: + return load_serialized_clvm( + clvm_filename=clvm_filename, + package_or_requirement=package_or_requirement, + include_standard_libraries=include_standard_libraries, + recompile=recompile, + ) diff --git a/resources/tests/lib/map.clinc b/resources/tests/lib/map.clinc new file mode 100644 index 000000000..016c3a0e4 --- /dev/null +++ b/resources/tests/lib/map.clinc @@ -0,0 +1,17 @@ +( + (defun map-with-rest (F L R) + (if L + (c (a F (list (f L))) (map-with-rest F (r L) R)) + R + ) + ) + + (defmacro map ARGS + (defun list-len (X) (if X (+ 1 (list-len (r X))) 0)) + + (if (= (list-len ARGS) 3) + (qq (map-with-rest (unquote (f ARGS)) (unquote (f (r ARGS))) (unquote (f (r (r ARGS)))))) + (qq (map-with-rest (unquote (f ARGS)) (unquote (f (r ARGS))) ())) + ) + ) +) diff --git a/resources/tests/lib/match.clinc b/resources/tests/lib/match.clinc new file mode 100644 index 000000000..d66593c55 --- /dev/null +++ b/resources/tests/lib/match.clinc @@ -0,0 +1,12 @@ + +( + (defun match (process remaining) + (if remaining + (if (a process (list (f remaining))) + (f remaining) + (match process (r remaining)) + ) + 0 + ) + ) +) diff --git a/resources/tests/lib/max.clinc b/resources/tests/lib/max.clinc new file mode 100644 index 000000000..5ec6d54f6 --- /dev/null +++ b/resources/tests/lib/max.clinc @@ -0,0 +1,13 @@ +( + (defun max_inner (myless best_so_far mylist) + (if (not mylist) best_so_far + (if (a myless (list best_so_far (f mylist))) + (max_inner myless (f mylist) (r mylist)) + (max_inner myless best_so_far (r mylist)) + ) + ) + ) + (defun max (myless mylist) + (max_inner myless (f mylist) (r mylist)) + ) +) diff --git a/resources/tests/lib/permutations.clinc b/resources/tests/lib/permutations.clinc new file mode 100644 index 000000000..9664c6aff --- /dev/null +++ b/resources/tests/lib/permutations.clinc @@ -0,0 +1,21 @@ +( + (defun permutations_inner (pre post agg) + (if (not post) + agg + (assign + myatom (f post) + newrest (r post) + (map (lambda ((& myatom) x) (c myatom x)) + (permutations (prepend pre newrest)) + (permutations_inner (c myatom pre) newrest agg) + ) + ) + ) + ) + (defun permutations (vals) + (if vals + (permutations_inner 0 vals 0) + (q ()) + ) + ) +) diff --git a/resources/tests/lib/prefix.clinc b/resources/tests/lib/prefix.clinc new file mode 100644 index 000000000..641723dad --- /dev/null +++ b/resources/tests/lib/prefix.clinc @@ -0,0 +1,16 @@ +( + (defmacro prefix ARGS + (defun compile-list (args) + (if args + (if (r args) + ;; We have at least 2 things left... recurse once. + (qq (c (unquote (f args)) (unquote (compile-list (r args))))) + ;; This is the last item, so we return it whole (improper list form). + (qq (unquote (f args))) + ) + 0 + ) + ) + (compile-list ARGS) + ) +) \ No newline at end of file diff --git a/resources/tests/lib/prepend.clinc b/resources/tests/lib/prepend.clinc new file mode 100644 index 000000000..2ea293409 --- /dev/null +++ b/resources/tests/lib/prepend.clinc @@ -0,0 +1,8 @@ +( + (defun prepend (a b) + (if a + (c (f a) (prepend (r a) b)) + b + ) + ) +) \ No newline at end of file diff --git a/resources/tests/lib/print.clinc b/resources/tests/lib/print.clinc new file mode 100644 index 000000000..95d459b36 --- /dev/null +++ b/resources/tests/lib/print.clinc @@ -0,0 +1,3 @@ +( + (defun print (R P) (if (all "$print$" R P) P P)) +) diff --git a/resources/tests/lib/program.py b/resources/tests/lib/program.py new file mode 100644 index 000000000..eff5badd0 --- /dev/null +++ b/resources/tests/lib/program.py @@ -0,0 +1,231 @@ +from __future__ import annotations + +import io +from typing import Any, Callable, Dict, Set, Tuple + +from chia_rs import run_chia_program, tree_hash +from clvm import SExp +from clvm.casts import int_from_bytes +from clvm.EvalError import EvalError +from clvm.serialize import sexp_from_stream, sexp_to_stream + +from chia.types.blockchain_format.sized_bytes import bytes32 +from chia.util.byte_types import hexstr_to_bytes +from chia.util.hash import std_hash + +from .tree_hash import sha256_treehash + +INFINITE_COST = 11000000000 + + +class Program(SExp): + """ + A thin wrapper around s-expression data intended to be invoked with "eval". + """ + + @classmethod + def parse(cls, f) -> "Program": + return sexp_from_stream(f, cls.to) + + def stream(self, f): + sexp_to_stream(self, f) + + @classmethod + def from_bytes(cls, blob: bytes) -> Program: + # this runs the program "1", which just returns the first argument. + # the first argument is the buffer we want to parse. This effectively + # leverages the rust parser and LazyNode, making it a lot faster to + # parse serialized programs into a python compatible structure + cost, ret = run_chia_program( + b"\x01", + blob, + 50, + 0, + ) + return Program.to(ret) + + @classmethod + def fromhex(cls, hexstr: str) -> "Program": + return cls.from_bytes(hexstr_to_bytes(hexstr)) + + def __bytes__(self) -> bytes: + f = io.BytesIO() + self.stream(f) # noqa + return f.getvalue() + + def __str__(self) -> str: + return bytes(self).hex() + + def at(self, position: str) -> "Program": + """ + Take a string of only `f` and `r` characters and follow the corresponding path. + + Example: + + `assert Program.to(17) == Program.to([10, 20, 30, [15, 17], 40, 50]).at("rrrfrf")` + + """ + v = self + for c in position.lower(): + if c == "f": + v = v.first() + elif c == "r": + v = v.rest() + else: + raise ValueError(f"`at` got illegal character `{c}`. Only `f` & `r` allowed") + return v + + def replace(self, **kwargs) -> "Program": + """ + Create a new program replacing the given paths (using `at` syntax). + Example: + ``` + >>> p1 = Program.to([100, 200, 300]) + >>> print(p1.replace(f=105) == Program.to([105, 200, 300])) + True + >>> print(p1.replace(rrf=[301, 302]) == Program.to([100, 200, [301, 302]])) + True + >>> print(p1.replace(f=105, rrf=[301, 302]) == Program.to([105, 200, [301, 302]])) + True + ``` + + This is a convenience method intended for use in the wallet or command-line hacks where + it would be easier to morph elements of an existing clvm object tree than to rebuild + one from scratch. + + Note that `Program` objects are immutable. This function returns a new object; the + original is left as-is. + """ + return _sexp_replace(self, self.to, **kwargs) + + def get_tree_hash_precalc(self, *args: bytes32) -> bytes32: + """ + Any values in `args` that appear in the tree + are presumed to have been hashed already. + """ + return sha256_treehash(self, set(args)) + + def get_tree_hash(self) -> bytes32: + return bytes32(tree_hash(bytes(self))) + + def run_with_cost(self, max_cost: int, args) -> Tuple[int, "Program"]: + prog_args = Program.to(args) + cost, r = run_chia_program(self.as_bin(), prog_args.as_bin(), max_cost, 0) + return cost, Program.to(r) + + def run(self, args) -> "Program": + cost, r = self.run_with_cost(INFINITE_COST, args) + return r + + # Replicates the curry function from clvm_tools, taking advantage of *args + # being a list. We iterate through args in reverse building the code to + # create a clvm list. + # + # Given arguments to a function addressable by the '1' reference in clvm + # + # fixed_args = 1 + # + # Each arg is prepended as fixed_args = (c (q . arg) fixed_args) + # + # The resulting argument list is interpreted with apply (2) + # + # (2 (1 . self) rest) + # + # Resulting in a function which places its own arguments after those + # curried in in the form of a proper list. + def curry(self, *args) -> "Program": + fixed_args: Any = 1 + for arg in reversed(args): + fixed_args = [4, (1, arg), fixed_args] + return Program.to([2, (1, self), fixed_args]) + + def uncurry(self) -> Tuple[Program, Program]: + def match(o: SExp, expected: bytes) -> None: + if o.atom != expected: + raise ValueError(f"expected: {expected.hex()}") + + try: + # (2 (1 . ) ) + ev, quoted_inner, args_list = self.as_iter() + match(ev, b"\x02") + match(quoted_inner.pair[0], b"\x01") + mod = quoted_inner.pair[1] + args = [] + while args_list.pair is not None: + # (4 (1 . ) ) + cons, quoted_arg, rest = args_list.as_iter() + match(cons, b"\x04") + match(quoted_arg.pair[0], b"\x01") + args.append(quoted_arg.pair[1]) + args_list = rest + match(args_list, b"\x01") + return Program.to(mod), Program.to(args) + except ValueError: # too many values to unpack + # when unpacking as_iter() + # or when a match() fails + return self, self.to(0) + except TypeError: # NoneType not subscriptable + # when an object is not a pair or atom as expected + return self, self.to(0) + except EvalError: # first of non-cons + # when as_iter() fails + return self, self.to(0) + + def as_int(self) -> int: + return int_from_bytes(self.as_atom()) + + def __deepcopy__(self, memo): + return type(self).from_bytes(bytes(self)) + + EvalError = EvalError + + +def _tree_hash(node: SExp, precalculated: Set[bytes32]) -> bytes32: + """ + Hash values in `precalculated` are presumed to have been hashed already. + """ + if node.listp(): + left = _tree_hash(node.first(), precalculated) + right = _tree_hash(node.rest(), precalculated) + s = b"\2" + left + right + else: + atom = node.as_atom() + if atom in precalculated: + return bytes32(atom) + s = b"\1" + atom + return bytes32(std_hash(s)) + + +NIL = Program.from_bytes(b"\x80") + + +def _sexp_replace(sexp: SExp, to_sexp: Callable[[Any], SExp], **kwargs) -> SExp: + # if `kwargs == {}` then `return sexp` unchanged + if len(kwargs) == 0: + return sexp + + if "" in kwargs: + if len(kwargs) > 1: + raise ValueError("conflicting paths") + return kwargs[""] + + # we've confirmed that no `kwargs` is the empty string. + # Now split `kwargs` into two groups: those + # that start with `f` and those that start with `r` + + args_by_prefix: Dict[str, SExp] = {} + for k, v in kwargs.items(): + c = k[0] + if c not in "fr": + raise ValueError("bad path containing %s: must only contain `f` and `r`") + args_by_prefix.setdefault(c, dict())[k[1:]] = v + + pair = sexp.pair + if pair is None: + raise ValueError("path into atom") + + # recurse down the tree + new_f = _sexp_replace(pair[0], to_sexp, **args_by_prefix.get("f", {})) + new_r = _sexp_replace(pair[1], to_sexp, **args_by_prefix.get("r", {})) + + return to_sexp((new_f, new_r)) diff --git a/resources/tests/lib/range.clinc b/resources/tests/lib/range.clinc new file mode 100644 index 000000000..dc1e61ca3 --- /dev/null +++ b/resources/tests/lib/range.clinc @@ -0,0 +1,11 @@ +( + (defun range_inner (next final) + (if (= next final) + 0 + (c next (range_inner (+ next 1) final)) + ) + ) + (defun range (i) + (range_inner 0 i) + ) +) \ No newline at end of file diff --git a/resources/tests/lib/reduce.clinc b/resources/tests/lib/reduce.clinc new file mode 100644 index 000000000..3251c79a7 --- /dev/null +++ b/resources/tests/lib/reduce.clinc @@ -0,0 +1,10 @@ + +( + ; From here to the meat should be in a standard library + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) +) diff --git a/resources/tests/lib/reverse.clinc b/resources/tests/lib/reverse.clinc new file mode 100644 index 000000000..389963ee9 --- /dev/null +++ b/resources/tests/lib/reverse.clinc @@ -0,0 +1,11 @@ +( + (defun reverse_inner (reversed rest) + (if rest + (reverse_inner (c (f rest) reversed) (r rest)) + reversed + ) + ) + (defun reverse (vals) + (reverse_inner 0 vals) + ) +) diff --git a/resources/tests/lib/shatree.clinc b/resources/tests/lib/shatree.clinc new file mode 100644 index 000000000..05bdb2699 --- /dev/null +++ b/resources/tests/lib/shatree.clinc @@ -0,0 +1,11 @@ +( + ;; hash a tree + ;; This is used to calculate a puzzle hash given a puzzle program. + (defun shatree + (TREE) + (if (l TREE) + (sha256 2 (shatree (f TREE)) (shatree (r TREE))) + (sha256 1 TREE) + ) + ) +) \ No newline at end of file diff --git a/resources/tests/lib/slice.clinc b/resources/tests/lib/slice.clinc new file mode 100644 index 000000000..2c98a09c5 --- /dev/null +++ b/resources/tests/lib/slice.clinc @@ -0,0 +1,10 @@ + +( + ; returns the first count elements of mylist + (defun slice (mylist count) + (if (print (list "slice inputs" nylist count) (not count)) + 0 + (c (f mylist) (slice (r mylist) (- count 1))) + ) + ) +) diff --git a/resources/tests/lib/smoke_test_deep_compare.clsp b/resources/tests/lib/smoke_test_deep_compare.clsp new file mode 100644 index 000000000..8df629518 --- /dev/null +++ b/resources/tests/lib/smoke_test_deep_compare.clsp @@ -0,0 +1,28 @@ +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include deep_compare.clinc) + + (map + (lambda ((want_cmp_val cmp_a cmp_b)) + (= (deep_compare cmp_a cmp_b) want_cmp_val) + ) + (q + (0 0 0) + (-1 () (1 14 5 4 3 2)) + (1 (1 14 5 4 3 2) ()) + (-1 "X" (1 2)) + (1 (1 2) "X") + (0 (3 2) (3 2)) + (-1 (3 1) (3 3)) + (1 (3 3) (3 1)) + (-1 (1 1) (2 1)) + (1 (3 1) (2 2)) + (-1 (2 2) (3 1)) + ) + ) + ) diff --git a/resources/tests/lib/smoke_test_permutations.clsp b/resources/tests/lib/smoke_test_permutations.clsp new file mode 100644 index 000000000..2ed3fbbcc --- /dev/null +++ b/resources/tests/lib/smoke_test_permutations.clsp @@ -0,0 +1,9 @@ +(mod (X) + (include *standard-cl-21*) + (include map.clinc) + (include prepend.clinc) + (include print.clinc) + (include permutations.clinc) + + (permutations X) + ) diff --git a/resources/tests/lib/smoke_test_sort.clsp b/resources/tests/lib/smoke_test_sort.clsp new file mode 100644 index 000000000..59b8a886e --- /dev/null +++ b/resources/tests/lib/smoke_test_sort.clsp @@ -0,0 +1,11 @@ +(mod (X) + (include *standard-cl-21*) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include reverse.clinc) + (include print.clinc) + + (sort (lambda (a b) (> b a)) X) + ) diff --git a/resources/tests/lib/sort.clinc b/resources/tests/lib/sort.clinc new file mode 100644 index 000000000..a9afed46a --- /dev/null +++ b/resources/tests/lib/sort.clinc @@ -0,0 +1,44 @@ + +( + (defun split_inner (@ everything (rest aggl aggr)) + (if rest + (split_inner (r rest) aggr (c (f rest) aggl)) + (r everything) + ) + ) + (defun split (mylist) + (split_inner mylist 0 0) + ) + (defun merge_inner (myless A B agg) + ; this should use continued if + (if (not A) + (prepend (reverse agg) B) + (if (not B) + (prepend (reverse agg) A) + (if (a myless (list (f A) (f B))) + (merge_inner myless (r A) B (c (f A) agg)) + (merge_inner myless A (r B) (c (f B) agg)) + ) + ) + ) + ) + (defun merge (myless a b) + (merge_inner myless a b 0) + ) + (defun sort-split (myless (a b)) + (merge myless (sort myless a) (sort myless b)) + ) + (defun sort (myless mylist) + (if mylist + (if (r mylist) + (assign (a b) (split mylist) + sa (sort myless a) + sb (sort myless b) + (merge myless sa sb) + ) + mylist + ) + () + ) + ) +) diff --git a/resources/tests/lib/steprun.py b/resources/tests/lib/steprun.py new file mode 100644 index 000000000..02db51339 --- /dev/null +++ b/resources/tests/lib/steprun.py @@ -0,0 +1,69 @@ +import binascii +import json +import os +from pathlib import Path +from typing import List + +# from chia.types.blockchain_format.program import Program +from clvm_rs import Program +from clvm_tools.binutils import assemble, disassemble + +from clvm_tools_rs import compile_clvm, compose_run_function, start_clvm_program + + +def compile_module_with_symbols(include_paths: List[Path], source: Path): + path_obj = Path(source) + file_path = path_obj.parent + file_stem = path_obj.stem + target_file = file_path / (file_stem + ".clvm.hex") + sym_file = file_path / (file_stem + ".sym") + # print(f"compile_clvm({path_obj.absolute()}, {str(target_file.absolute().as_posix())}, {include_paths}, True)") + compile_result = compile_clvm( + str(path_obj.resolve()), str(target_file.absolute()), [str(p) for p in include_paths], True + ) + print(f"Writing to {target_file} {compile_result}") + # symbols = compile_result["symbols"] + # if len(symbols) != 0: + # with open(str(sym_file.absolute()), "w") as symfile: + # symfile.write(json.dumps(symbols)) + + +def run_until_end(p): + last = None + location = None + + while not p.is_ended(): + step_result = p.step() + if step_result is not None: + last = step_result + if "Print" in last: + to_print = last["Print"] + if "Print-Location" in last: + print(f"{last['Print-Location']}: print {to_print}") + else: + print(f"print {to_print}") + + return last + + +def diag_run_clvm(program, args, symbols): + hex_form_of_program = binascii.hexlify(bytes(program)).decode("utf8") + hex_form_of_args = binascii.hexlify(bytes(args)).decode("utf8") + symbols = json.loads(open(symbols).read()) + p = start_clvm_program( + hex_form_of_program, hex_form_of_args, symbols, None + ) + report = run_until_end(p) + if "Failure" in report: + raise Exception(report) + else: + return assemble(report["Final"]) + + +if __name__ == "__main__": + # smoke test + import sys + + program = Program.fromhex(open(sys.argv[1]).read()) + args = Program.fromhex(open(sys.argv[2]).read()) + diag_run_clvm(program, args) diff --git a/resources/tests/lib/tree_hash.py b/resources/tests/lib/tree_hash.py new file mode 100644 index 000000000..1e59e9b7c --- /dev/null +++ b/resources/tests/lib/tree_hash.py @@ -0,0 +1,62 @@ +""" +This is an implementation of `sha256_treehash`, used to calculate +puzzle hashes in clvm. + +This implementation goes to great pains to be non-recursive so we don't +have to worry about blowing out the python stack. +""" + +from __future__ import annotations + +from typing import Callable, List, Optional, Set + +from clvm import CLVMObject + +from chia.types.blockchain_format.sized_bytes import bytes32 +from chia.util.hash import std_hash + +Op = Callable[[List["CLVMObject"], List["Op"], Set[bytes32]], None] + + +def sha256_treehash(sexp: CLVMObject, precalculated: Optional[Set[bytes32]] = None) -> bytes32: + """ + Hash values in `precalculated` are presumed to have been hashed already. + """ + + if precalculated is None: + precalculated = set() + + def handle_sexp(sexp_stack: List[CLVMObject], op_stack: List[Op], precalculated: Set[bytes32]) -> None: + sexp = sexp_stack.pop() + if sexp.pair: + p0, p1 = sexp.pair + sexp_stack.append(p0) + sexp_stack.append(p1) + op_stack.append(handle_pair) + op_stack.append(handle_sexp) + op_stack.append(roll) + op_stack.append(handle_sexp) + else: + if sexp.atom in precalculated: + r = sexp.atom + else: + r = std_hash(b"\1" + sexp.atom) + sexp_stack.append(r) + + def handle_pair(sexp_stack: List[CLVMObject], op_stack: List[Op], precalculated: Set[bytes32]) -> None: + p0 = sexp_stack.pop() + p1 = sexp_stack.pop() + sexp_stack.append(std_hash(b"\2" + p0 + p1)) + + def roll(sexp_stack: List[CLVMObject], op_stack: List[Op], precalculated: Set[bytes32]) -> None: + p0 = sexp_stack.pop() + p1 = sexp_stack.pop() + sexp_stack.append(p0) + sexp_stack.append(p1) + + sexp_stack = [sexp] + op_stack: List[Op] = [handle_sexp] + while len(op_stack) > 0: + op = op_stack.pop() + op(sexp_stack, op_stack, precalculated) + return bytes32(sexp_stack[0]) diff --git a/resources/tests/lib/utils.clinc b/resources/tests/lib/utils.clinc new file mode 100644 index 000000000..7d754e001 --- /dev/null +++ b/resources/tests/lib/utils.clinc @@ -0,0 +1,17 @@ +( + (defmacro ifc ARGS + (defun list-length (lst) + (if (l lst) + (+ 1 (list-length (r lst))) + 0 + ) + ) + (defun do-continued-if (ARGS) + (if (= (list-length ARGS) 3) + (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS))))))) + (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (unquote (do-continued-if (r (r ARGS)))))) + ) + ) + (qq (a (unquote (do-continued-if ARGS)) @)) + ) +) diff --git a/support/test-game-referee.sh b/support/test-game-referee.sh new file mode 100755 index 000000000..31e28a93a --- /dev/null +++ b/support/test-game-referee.sh @@ -0,0 +1,16 @@ +#!/bin/bash -x + +if [ "x$1" = x ] ; then + echo "usage: test-game-referee.sh [game-referee-version]" + exit 1 +fi + +REF_SUBDIR="$1" + +python -m pip install --upgrade pip +python -m pip install chia_rs==0.2.5 +python -m pip install clvm_tools +python -m pip install pytest + +export PYTHONPATH=$PWD/resources/tests:.:$PYTHONPATH +(cd "${REF_SUBDIR}" && pytest -s .) From a55e7d33a41cd3dc2592e15db01fa56509a3beff Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 17 Aug 2023 14:24:49 -0700 Subject: [PATCH 108/196] Feature flag extraction is from nightly (so far) and not needed here (yet) --- .github/workflows/extensive-tests.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/extensive-tests.yml b/.github/workflows/extensive-tests.yml index b4be9eab8..6bf997da7 100644 --- a/.github/workflows/extensive-tests.yml +++ b/.github/workflows/extensive-tests.yml @@ -83,13 +83,6 @@ jobs: # Ensure an empty .cargo-lock file exists. touch target/release/.cargo-lock - - name: Set up feature flags to use - shell: bash - run: | - python -m pip install tomlkit - USE_FEATURES=$(./support/feature-fishing.py) - echo "USE_FEATURES=${USE_FEATURES}" >> "$GITHUB_ENV" - - name: Install clvm_tools_rs wheel if: ${{ !startsWith(matrix.os, 'windows') }} run: | From 78e3dc2e5f4141fd4715fc76e83db8ec11797d3e Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 17 Aug 2023 20:17:51 -0700 Subject: [PATCH 109/196] Ensure test files are properly organized so each version of the game chialisp we're testing is separate --- .../game-referee-after-cl21/handcalc.clinc | 140 ----- .../game-referee-after-cl21/handcalc_a.clinc | 256 ---------- .../smoke_test_deep_compare.clsp | 28 - .../smoke_test_permutations.clsp | 9 - .../smoke_test_sort.clsp | 11 - .../spacehandcalc.clinc | 104 ---- .../test_handcalc.clsp | 379 -------------- .../test_handcalc_b.clsp | 377 -------------- .../test_library_basics.py | 165 ------ .../test_permutations.clsp | 63 --- .../game-referee-after-cl21/test_prepend.clsp | 5 - .../game-referee-after-cl21/test_range.clsp | 6 - .../game-referee-after-cl21/test_reverse.clsp | 6 - .../game-referee-after-cl21/test_sort.clsp | 37 -- .../game-referee-after-cl21/testnoncegame.py | 33 -- .../game-referee-after-cl21/testreferee.py | 479 ------------------ .../testrockpaperscissors.py | 48 -- .../all-in-list.clinc | 0 .../assert.clinc | 0 .../{lib => game-referee-in-cl21}/busy.clinc | 0 .../condition_codes.clinc | 0 .../curry-and-treehash.clinc | 0 .../{lib => game-referee-in-cl21}/curry.clinc | 0 .../deep_compare.clinc | 0 .../filtermap.clinc | 0 .../flatten.clinc | 0 .../{lib => game-referee-in-cl21}/last.clinc | 0 .../{lib => game-referee-in-cl21}/len.clinc | 0 .../{lib => game-referee-in-cl21}/map.clinc | 0 .../{lib => game-referee-in-cl21}/match.clinc | 0 .../{lib => game-referee-in-cl21}/max.clinc | 0 .../permutations.clinc | 0 .../prefix.clinc | 0 .../prepend.clinc | 0 .../{lib => game-referee-in-cl21}/print.clinc | 0 .../{lib => game-referee-in-cl21}/range.clinc | 0 .../reduce.clinc | 0 .../reverse.clinc | 0 .../shatree.clinc | 0 .../{lib => game-referee-in-cl21}/slice.clinc | 0 .../{lib => game-referee-in-cl21}/sort.clinc | 0 .../{lib => game-referee-in-cl21}/utils.clinc | 0 42 files changed, 2146 deletions(-) delete mode 100644 resources/tests/game-referee-after-cl21/handcalc.clinc delete mode 100644 resources/tests/game-referee-after-cl21/handcalc_a.clinc delete mode 100644 resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp delete mode 100644 resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp delete mode 100644 resources/tests/game-referee-after-cl21/smoke_test_sort.clsp delete mode 100644 resources/tests/game-referee-after-cl21/spacehandcalc.clinc delete mode 100644 resources/tests/game-referee-after-cl21/test_handcalc.clsp delete mode 100644 resources/tests/game-referee-after-cl21/test_handcalc_b.clsp delete mode 100644 resources/tests/game-referee-after-cl21/test_library_basics.py delete mode 100644 resources/tests/game-referee-after-cl21/test_permutations.clsp delete mode 100644 resources/tests/game-referee-after-cl21/test_prepend.clsp delete mode 100644 resources/tests/game-referee-after-cl21/test_range.clsp delete mode 100644 resources/tests/game-referee-after-cl21/test_reverse.clsp delete mode 100644 resources/tests/game-referee-after-cl21/test_sort.clsp delete mode 100644 resources/tests/game-referee-after-cl21/testnoncegame.py delete mode 100644 resources/tests/game-referee-after-cl21/testreferee.py delete mode 100644 resources/tests/game-referee-after-cl21/testrockpaperscissors.py rename resources/tests/{lib => game-referee-in-cl21}/all-in-list.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/assert.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/busy.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/condition_codes.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/curry-and-treehash.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/curry.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/deep_compare.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/filtermap.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/flatten.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/last.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/len.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/map.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/match.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/max.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/permutations.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/prefix.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/prepend.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/print.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/range.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/reduce.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/reverse.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/shatree.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/slice.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/sort.clinc (100%) rename resources/tests/{lib => game-referee-in-cl21}/utils.clinc (100%) diff --git a/resources/tests/game-referee-after-cl21/handcalc.clinc b/resources/tests/game-referee-after-cl21/handcalc.clinc deleted file mode 100644 index 6317733f4..000000000 --- a/resources/tests/game-referee-after-cl21/handcalc.clinc +++ /dev/null @@ -1,140 +0,0 @@ - -; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace -; suits are 1-4 with no particular labelling -; takes a list of cards (rank . suit) and returns the value of the best poker -; hand which can be made with them -; returned list is hand type followed by cards in descending order -; doesn't work for ten or more cards if there are multiple flushes -; all sorting is done highest to lowest -( - (defconstant STRAIGHT_FLUSH 9) - (defconstant FOUR_OF_A_KIND 8) - (defconstant FULL_HOUSE 7) - (defconstant FLUSH 6) - (defconstant STRAIGHT 5) - (defconstant THREE_OF_A_KIND 4) - (defconstant TWO_PAIR 3) - (defconstant PAIR 2) - (defconstant HIGH_CARD 1) - (defun find_flush_inner (suits last count) - (if (not suits) - 0 - (if (= (f suits) last) - (if (= count 4) - last - (find_flush_inner (r suits) last (+ count 1)) - ) - (find_flush_inner (r suits) (f suits) 1) - ) - ) - ) - ; returns the flush suit or 0 if there isn't any - ; suits must be clustered/sorted - (defun find_flush (suits) - (find_flush_inner (sort (lambda (x y) (deep> x y)) suits) 0 0) - ) - (defun straight_high_inner (ranks started_ace last count) - (if (not ranks) - ; at the end of the list - (if (logand (= last 2) (= count 4) started_ace) - ; ace to five - 5 - ; no straight - 0 - ) - (if (= last (f ranks)) - ; skip identical cards - (straight_high_inner (r ranks) started_ace last count) - ; if the partial straight continues - (if (= (f ranks) (- last 1)) - (if (= count 4) - ; found a straight, add 3 to last because next and last are included - (+ last 3) - ; keep looking for a straight with the count going up by one - (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) - ) - ; reset the count - (straight_high_inner (r ranks) started_ace (f ranks) 1) - ) - ) - ) - ) - ; returns the high card of a straight or 0 if there isn't any - ; ranks must be sorted in descending order - (defun straight_high (ranks) - (straight_high_inner ranks (= (f ranks) 14) 0 0) - ) - (defun group_by_count_inner (items last count) - (if (not items) - (list (c count last)) - (if (= (f items) last) - (group_by_count_inner (r items) last (+ count 1)) - (assign val (group_by_count_inner (r items) (f items) 1) - (c (c count last) val) - ) - ) - ) - ) - (defun group_by_count (items) - (group_by_count_inner items (f items) 0) - ) - (defun handcalc (cards) - (assign-lambda - first (lambda (x) (f x)) - rest (lambda (x) (r x)) - fsuit (find_flush (map rest cards)) - max_flush (if (not fsuit) - 0 - (assign-lambda - fnosuits - (sort - (lambda (x y) (deep> x y)) - (filtermap - (lambda ((& fsuit) (card_rank . card_suit)) - (if (= fsuit card_suit) - card_rank - 0 - ) - ) - cards - 0 - ) - ) - - fsh (straight_high fnosuits) - (if fsh - (list STRAIGHT_FLUSH fsh) - (c FLUSH (slice fnosuits 5)) - ) - ) - ) - nosuits (sort (lambda (x y) (deep> x y)) (map first cards)) - sh (straight_high nosuits) - max_straight (if sh - (list STRAIGHT sh) - 0 - ) - groups (sort (lambda (x y) (deep> x y)) (group_by_count nosuits)) - (top_count . top_card) (f groups) - (second_count . second_card) (f (r groups)) - topcards (map rest groups) - max_group (if (= top_count 1) - (c HIGH_CARD (slice topcards 5)) - (if (= top_count 2) - (if (= second_count 1) - (c PAIR (slice topcards 4)) - (c TWO_PAIR (slice topcards 3)) - ) - (if (= top_count 3) - (if (= second_count 1) - (c THREE_OF_A_KIND (slice topcards 3)) - (c FULL_HOUSE (slice topcards 2)) - ) - (c FOUR_OF_A_KIND (slice topcards 2)) - ) - ) - ) - (max (lambda (x y) (deep< x y)) (list max_flush max_straight max_group)) - ) - ) -) diff --git a/resources/tests/game-referee-after-cl21/handcalc_a.clinc b/resources/tests/game-referee-after-cl21/handcalc_a.clinc deleted file mode 100644 index 06c326392..000000000 --- a/resources/tests/game-referee-after-cl21/handcalc_a.clinc +++ /dev/null @@ -1,256 +0,0 @@ - -; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace -; suits are 1-4 with no particular labelling -; takes a list of cards (rank . suit) and returns the value of the best poker -; hand which can be made with them -; returned list is hand type followed by cards in descending order -; doesn't work for ten or more cards if there are multiple flushes -; all sorting is done highest to lowest -( - (defconstant STRAIGHT_FLUSH 9) - (defconstant FOUR_OF_A_KIND 8) - (defconstant FULL_HOUSE 7) - (defconstant FLUSH 6) - (defconstant STRAIGHT 5) - (defconstant THREE_OF_A_KIND 4) - (defconstant TWO_PAIR 3) - (defconstant PAIR 2) - (defconstant HIGH_CARD 1) - (defun hand_compare (a b) - (if (= (f a) (f b)) - (if (r a) - (hand_compare (r a) (r b)) - 0 - ) - (- (* 2 (> (f a) (f b))) 1) - ) - ) - (defun hand< (a b) - (= (hand_compare a b) -1) - ) - (defun merge (a b) - (if (not a) - b - (if (not b) - a - (if (> (f a) (f b)) - (c (f a) (merge (r a) b)) - (c (f b) (merge a (r b))) - ) - ) - ) - ) - ; Sorts atoms into descending order - ; This is optimized for sorting short lists - ; A more general function would return a list of lists of ascending sizes - ; to be merged - (defun atomsort ((@ firstpos (first @ secondpos (second @ thirdpos (third . remaining))))) - (if firstpos - (if secondpos - (if thirdpos - (assign-lambda - mylist - (if (> first second) - (if (> second third) - (list first second third) - (if (> first third) - (list first third second) - (list third first second) - ) - ) - (if (> first third) - (list second first third) - (if (> second third) - (list second third first) - (list third second first) - ) - ) - ) - (merge mylist (atomsort remaining)) - ) - (if (> first second) - firstpos - (list second first) - ) - ) - firstpos - ) - 0 - ) - ) - (defun count_suits_2 ((@ suits (firstsuit . remaining))) - (if (not suits) - (c (c 0 0) (c 0 0)) - (assign-lambda ((@ cd (clubs . diamonds)) . (@ hs (hearts . spades))) (count_suits remaining) - (if (= firstsuit 1) - (c (c (+ clubs 1) diamonds) hs) - (if (= firstsuit 2) - (c (c clubs (+ diamonds 1)) hs) - (if (= firstsuit 3) - (c cd (c (+ hearts 1) spades)) - (c cd (c hearts (+ spades 1))) - ) - ) - ) - ) - ) - ) - (defun find_flush_2 (suits) - (assign-lambda ((clubs . diamonds) . (hearts . spades)) (count_suits suits) - (if (> clubs 4) - 1 - (if (> diamonds 4) - 2 - (if (> hearts 4) - 3 - (if (> spades 4) - 4 - 0 - ) - ) - ) - ) - ) - ) - (defun count_suits (suits) - (if suits - (+ (count_suits (r suits)) (ash 1 (* 4 (- (f suits) 1)))) - 0 - ) - ) - (defun find_flush (suits) - (assign-lambda - myvals (count_suits suits) - (if (> (logand myvals 0xF000) 0x4000) - 4 - (if (> (logand myvals 0x0F00) 0x0400) - 3 - (if (> (logand myvals 0x00F0) 0x0040) - 2 - (if (> (logand myvals 0x0F) 0x04) - 1 - 0 - ) - ) - ) - ) - ) - ) - (defun straight_high_inner (ranks last count) - (if (not ranks) - (if (logand (= last 2) (= count 4)) - ; maybe ace to five - 5 - 0 - ) - (if (= last (f ranks)) - ; skip identical cards - (straight_high_inner (r ranks) last count) - ; if the partial straight continues - (if (= (f ranks) (- last 1)) - (if (= count 4) - ; found a straight, add 3 to last because next and last are included - (+ last 3) - ; keep looking for a straight with the count going up by one - (straight_high_inner (r ranks) (f ranks) (+ count 1)) - ) - ; reset the count - (straight_high_inner (r ranks) (f ranks) 1) - ) - ) - ) - ) - ; returns the high card of a straight or 0 if there isn't any - ; ranks must be sorted in descending order - (defun straight_high (ranks) - (assign-lambda high (straight_high_inner ranks 0 0) - (if (= high 5) - (* (= (f ranks) 14) 5) - high - ) - ) - ) - (defun group_by_count_inner (items last count) - (if (not items) - (list (logior (lsh count 4) last)) - (if (= (f items) last) - (group_by_count_inner (r items) last (+ count 1)) - (assign-inline val (group_by_count_inner (r items) (f items) 1) - (c (logior (lsh count 4) last) val) - ) - ) - ) - ) - (defun group_by_count (items) - (group_by_count_inner items (f items) 0) - ) - (defun handcalc (cards) - (assign-lambda - first (lambda (x) (f x)) - rest (lambda (x) (r x)) - fsuit (find_flush (map rest cards)) - max_flush (if (not fsuit) - (list 0) - (assign-lambda - flushcards - (filtermap - (lambda ((& fsuit) (card_rank . card_suit)) - (if (= fsuit card_suit) - card_rank - 0 - ) - ) - cards - 0 - ) - flushranks (atomsort flushcards) - fsh (straight_high flushranks) - (if fsh - (list STRAIGHT_FLUSH fsh) - (c FLUSH (slice flushranks 5)) - ) - ) - ) - ranks (atomsort (map first cards)) - sh (straight_high ranks) - max_straight (if sh - (list STRAIGHT sh) - (list 0) - ) - groups (map - (lambda (myval) (c (lsh myval -4) (logand myval 0x0F))) - (atomsort (group_by_count ranks)) - ) - (top_count . top_card) (f groups) - (second_count . second_card) (f (r groups)) - topcards (map rest groups) - max_group (if (= top_count 1) - (c HIGH_CARD (slice topcards 5)) - (if (= top_count 2) - (if (= second_count 1) - (c PAIR (slice topcards 4)) - (c TWO_PAIR (slice topcards 3)) - ) - (if (= top_count 3) - (if (= second_count 1) - (c THREE_OF_A_KIND (slice topcards 3)) - (c FULL_HOUSE (slice topcards 2)) - ) - (c FOUR_OF_A_KIND (slice topcards 2)) - ) - ) - ) - ; max of max_flush max_straight and max_group - (if (> (f max_flush) (f max_straight)) - (if (> (f max_flush) (f max_group)) - max_flush - max_group - ) - (if (> (f max_straight) (f max_group)) - max_straight - max_group - ) - ) - ) - ) -) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp deleted file mode 100644 index 8df629518..000000000 --- a/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp +++ /dev/null @@ -1,28 +0,0 @@ -(mod () - (include *standard-cl-21*) - (include print.clinc) - (include prepend.clinc) - (include sort.clinc) - (include assert.clinc) - (include map.clinc) - (include deep_compare.clinc) - - (map - (lambda ((want_cmp_val cmp_a cmp_b)) - (= (deep_compare cmp_a cmp_b) want_cmp_val) - ) - (q - (0 0 0) - (-1 () (1 14 5 4 3 2)) - (1 (1 14 5 4 3 2) ()) - (-1 "X" (1 2)) - (1 (1 2) "X") - (0 (3 2) (3 2)) - (-1 (3 1) (3 3)) - (1 (3 3) (3 1)) - (-1 (1 1) (2 1)) - (1 (3 1) (2 2)) - (-1 (2 2) (3 1)) - ) - ) - ) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp b/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp deleted file mode 100644 index 2ed3fbbcc..000000000 --- a/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp +++ /dev/null @@ -1,9 +0,0 @@ -(mod (X) - (include *standard-cl-21*) - (include map.clinc) - (include prepend.clinc) - (include print.clinc) - (include permutations.clinc) - - (permutations X) - ) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp b/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp deleted file mode 100644 index 59b8a886e..000000000 --- a/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp +++ /dev/null @@ -1,11 +0,0 @@ -(mod (X) - (include *standard-cl-21*) - (include prepend.clinc) - (include sort.clinc) - (include assert.clinc) - (include map.clinc) - (include reverse.clinc) - (include print.clinc) - - (sort (lambda (a b) (> b a)) X) - ) diff --git a/resources/tests/game-referee-after-cl21/spacehandcalc.clinc b/resources/tests/game-referee-after-cl21/spacehandcalc.clinc deleted file mode 100644 index 3bfae65ca..000000000 --- a/resources/tests/game-referee-after-cl21/spacehandcalc.clinc +++ /dev/null @@ -1,104 +0,0 @@ - -; ranks are 1-13 with 1 being two, 12 being king, and 13 being ace -; there are no suits, flushes, or ace-to-four straights -; takes a list of card ranks and returns the value of the best poker -; hand which can be made with them -; returned list is hand type followed by cards in descending order -; all sorting is done highest to lowest -( - (include *standard-cl-22*) - (include sort.clinc) - (include deep_compare.clinc) - (include filtermap.clinc) - (include slice.clinc) - (include max.clinc) - (defconstant FIVE_OF_A_KIND 10) - (defconstant STRAIGHT_FLUSH 9) - (defconstant FOUR_OF_A_KIND 8) - (defconstant FULL_HOUSE 7) - (defconstant FLUSH 6) - (defconstant STRAIGHT 5) - (defconstant THREE_OF_A_KIND 4) - (defconstant TWO_PAIR 3) - (defconstant PAIR 2) - (defconstant HIGH_CARD 1) - (defun straight_high_inner (ranks last count) - (if (not ranks) - ; at the end of the list - 0 - (if (= last (f ranks)) - ; skip identical cards - (straight_high_inner (r ranks) started_ace last count) - ; if the partial straight continues - (if (= (f ranks) (- last 1)) - (if (= count 4) - ; found a straight, add 3 to last because next and last are included - (+ last 3) - ; keep looking for a straight with the count going up by one - (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) - ) - ; reset the count - (straight_high_inner (r ranks) started_ace (f ranks) 1) - ) - ) - ) - ) - ; returns the high card of a straight or 0 if there isn't any - ; ranks must be sorted in descending order - (defun straight_high (ranks) - (straight_high_inner (ranks (= (f ranks) 13) 0 0)) - ) - (defun group_by_count_inner (items last count) - (if (not items) - 0 - (if (= (f items) last) - (group_by_count_inner (r items) last (+ count 1)) - (assign val (group_by_count_inner (r items) (f items) 1) - (if last - (c (c count last) val) - val - ) - ) - ) - ) - ) - (defun group_by_count (items) - (group_by_count_inner items 0 0) - ) - (defun space_hand_calc (cards) - (assign - rest (lambda (x) (r x)) - greater (lambda (x y) (> x y)) - ranks (sort greater cards) - sh (straight_high ranks) - max_straight (if sh - (list STRAIGHT sh) - 0 - ) - groups (sort deep> (group_by_count ranks)) - (top_count . top_card) (f groups) - (second_count . second_card) (f (r groups)) - topcards (map rest groups) - max_group (if (= top_count 1) - (c HIGH_CARD (slice topcards 5)) - (if (= top_count 2) - (if (= second_count 1) - (c PAIR (slice topcards 4)) - (c TWO_PAIR (slice topcards 3)) - ) - (if (= top_count 3) - (if (= second_count 1) - (c THREE_OF_A_KIND (slice topcards 3)) - (c FULL_HOUSE (slice topcards 2)) - ) - (if (= top_count 4) - (c FOUR_OF_A_KIND (slice topcards 2)) - (c FIVE_OF_A_KIND (slice topcards 1)) - ) - ) - ) - ) - (max deep< (list max_straight max_group)) - ) - ) -) diff --git a/resources/tests/game-referee-after-cl21/test_handcalc.clsp b/resources/tests/game-referee-after-cl21/test_handcalc.clsp deleted file mode 100644 index 16c46f664..000000000 --- a/resources/tests/game-referee-after-cl21/test_handcalc.clsp +++ /dev/null @@ -1,379 +0,0 @@ - -(mod () - (include *standard-cl-21*) - (include deep_compare.clinc) - (include assert.clinc) - (include reverse.clinc) - (include prepend.clinc) - (include map.clinc) - (include filtermap.clinc) - (include slice.clinc) - (include print.clinc) - (include sort.clinc) - (include max.clinc) - (include handcalc.clinc) - - (defun runtests_inner ((myfunc firstarg secondarg . remaining)) - (assign-lambda - firstval (handcalc firstarg) - secondval (handcalc secondarg) - (assert - (a myfunc (list firstval secondval)) - (deep= firstval (handcalc (reverse firstarg))) - (deep= secondval (handcalc (reverse secondarg))) - (if remaining - (runtests_inner remaining) - 0 - ) - ) - ) - ) - - (defun runtests tests (if tests (runtests_inner tests) ())) - - ;; Join these up when large application bug is fixed. - (runtests - ; all beats both emerge over and measure higher - ; straight flush with higher kicker ties - ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 - deep= - (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) - (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) - ; straight flushes of different suits tie - ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 - deep= - (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) - (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) - ; higher straight flush beats lower straight flush - ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 - deep> - (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) - (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 - deep= - (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) - (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) - ; lower (2-6) straight flush beats ace to four straight flush - ; 61 51 41 31 21 > A2 52 42 32 22 - deep> - (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) - ; A1 61 51 41 31 21 = 61 51 41 31 21 - deep= - (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - ; ace to four straight flush with higher kicker ties - ; A2 52 42 32 22 61 = A1 51 41 31 21 71 - deep= - (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) - (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) - ; ace to four straight flushes of different suits tie - ; A1 51 41 31 21 = A2 52 42 32 22 - deep= - (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) - ; ace to four straight flush beats four of a kind - ; A1 51 41 31 21 > K1 K2 K3 K4 J1 - deep> - (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) - ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 - deep= - (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - ; four of a kind with higher kicker wins - ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 - deep> - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) - ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 - deep= - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) - ; four of a kind with higher second kicker ties - ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 - deep= - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) - ; higher four of a kind beats lower four of a kind - ; K1 K2 K3 K4 21 > 31 32 33 34 A1 - deep> - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) - (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) - ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 - deep= - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) - ; four of a kind beats full house - ; 21 22 23 24 31 > A1 A2 A3 K1 K2 - deep> - (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) - ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 - deep= - (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) - (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) - ; full house with higher set wins - ; 51 52 53 21 22 > 31 32 33 71 72 - deep> - (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) - (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) - ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 - deep= - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) - ; full house with same set and higher pair wins - ; 51 52 53 41 42 > 51 52 53 31 32 - deep> - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) - (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) - ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 - deep= - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) - ; full house ties with two sets - ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 - deep= - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) - ; full house beats flush - ; 51 52 53 41 42 > A1 Q1 T1 81 71 - deep> - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) - (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) - ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 - deep= - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) - ; higher flush beats lower flush - ; A1 61 51 41 31 > K1 Q1 J1 T1 81 - deep> - (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) - (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) - ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 - deep= - (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) - (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) - ; flush with higher second card wins - ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 - deep> - (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) - (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) - ; flush with higher third card wins - ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 - deep> - (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) - (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) - ; flush with higher fourth card wins - ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 - deep> - (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) - (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) - ; flush with higher fifth card wins - ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 - deep> - (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) - (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) - ; flushes of different suits tie - ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 - deep= - (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) - (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) - ; same flush with higher sixth card ties - ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 - deep= - (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) - (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) - ; flush beats straight - ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 - deep> - (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) - ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) - (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) - ; straight with higher kicker ties - ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) - ; straights of different suits tie - ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) - (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) - ; higher straight beats lower straight - ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 - deep> - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) - (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) - (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) - ; lower (2-6) straight beats ace to four straight - ; 61 52 43 34 21 > A1 52 43 34 21 - deep> - (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - ; A1 62 53 44 31 22 = 62 53 44 31 22 - deep= - (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) - (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) - ; ace to four straight with higher kicker ties - ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 - deep= - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) - ; ace to fours of different suits tie - ; A1 52 43 34 21 = A2 53 44 31 22 - deep= - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) - ; ace to four straight beats set - ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 - deep> - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) - ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 - deep= - (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) - ; higher set wins - ; 71 72 73 34 21 > 51 52 53 A4 K1 - deep> - (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) - (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) - ; set with higher first kicker wins - ; 71 72 73 A1 22 > 71 72 73 K1 Q2 - deep> - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) - (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) - ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 - deep= - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) - ; set with higher second kicker wins - ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 - deep> - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) - ; set with higher third kicker ties - ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 - deep= - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) - ; set beats two pair - ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 - deep> - (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) - ; two pair with higher high pair wins - ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 - deep> - (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) - (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) - ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 - deep= - (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) - (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) - ; two pair with tied higher pair and higher lower pair wins - ; K1 K2 71 72 23 > K1 K2 63 64 A1 - deep> - (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) - (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) - ; two pair with higher kicker wins - ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 - deep> - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) - ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 - deep= - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) - ; two pair with higher second kicker ties - ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 - deep= - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) - ; two pair beats pair - ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 - deep> - (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) - ; higher pair wins - ; 71 72 53 44 31 > 61 62 A3 K4 Q1 - deep> - (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) - (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) - ; tied pair with higher first kicker wins - ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 - deep> - (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) - (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) - ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 - deep= - (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) - (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) - ; tied pair with higher second kicker wins - ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 - deep> - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) - (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) - ; tied pair with higher third kicker wins - ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 - deep> - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) - ; tied pair with higher fourth kicker ties - ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 - deep= - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) - ; pair beats high card - ; 21 22 33 44 51 > A1 Q2 J3 T4 91 - deep> - (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) - (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) - ; higher high card wins - ; A1 22 33 44 61 > K1 Q2 J3 T4 81 - deep> - (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) - (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) - ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 - deep= - (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) - (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) - ; higher second card wins - ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 - deep> - (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) - (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) - ; higher third card wins - ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 - deep> - (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) - (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) - ; higher fourth card wins - ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 - deep> - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) - (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) - ; higher fifth card wins - ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 - deep> - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) - ; higher sixth card ties - ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) - ; high cards of different suits ties - ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) - (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) - ) -) diff --git a/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp b/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp deleted file mode 100644 index 674bbd414..000000000 --- a/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp +++ /dev/null @@ -1,377 +0,0 @@ - -(mod () - (include *standard-cl-21*) - (include deep_compare.clinc) - (include assert.clinc) - (include reverse.clinc) - (include prepend.clinc) - (include map.clinc) - (include filtermap.clinc) - (include slice.clinc) - (include print.clinc) - (include handcalc.clinc) - - (defun runtests_inner ((myfunc firstarg secondarg . remaining)) - (assign-lambda - firstval (handcalc firstarg) - secondval (handcalc secondarg) - (assert - (a myfunc (list firstval secondval)) - (deep= firstval (handcalc (reverse firstarg))) - (deep= secondval (handcalc (reverse secondarg))) - (if remaining - (runtests_inner remaining) - 0 - ) - ) - ) - ) - - (defun runtests tests (if tests (runtests_inner tests) ())) - - ;; Join these up when large application bug is fixed. - (runtests - ; all beats both emerge over and measure higher - ; straight flush with higher kicker ties - ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 - deep= - (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) - (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) - ; straight flushes of different suits tie - ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 - deep= - (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) - (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) - ; higher straight flush beats lower straight flush - ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 - deep> - (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) - (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 - deep= - (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) - (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) - ; lower (2-6) straight flush beats ace to four straight flush - ; 61 51 41 31 21 > A2 52 42 32 22 - deep> - (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) - ; A1 61 51 41 31 21 = 61 51 41 31 21 - deep= - (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - ; ace to four straight flush with higher kicker ties - ; A2 52 42 32 22 61 = A1 51 41 31 21 71 - deep= - (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) - (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) - ; ace to four straight flushes of different suits tie - ; A1 51 41 31 21 = A2 52 42 32 22 - deep= - (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) - ; ace to four straight flush beats four of a kind - ; A1 51 41 31 21 > K1 K2 K3 K4 J1 - deep> - (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) - ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 - deep= - (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) - ; four of a kind with higher kicker wins - ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 - deep> - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) - ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 - deep= - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) - ; four of a kind with higher second kicker ties - ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 - deep= - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) - ; higher four of a kind beats lower four of a kind - ; K1 K2 K3 K4 21 > 31 32 33 34 A1 - deep> - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) - (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) - ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 - deep= - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) - (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) - ; four of a kind beats full house - ; 21 22 23 24 31 > A1 A2 A3 K1 K2 - deep> - (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) - ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 - deep= - (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) - (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) - ; full house with higher set wins - ; 51 52 53 21 22 > 31 32 33 71 72 - deep> - (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) - (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) - ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 - deep= - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) - ; full house with same set and higher pair wins - ; 51 52 53 41 42 > 51 52 53 31 32 - deep> - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) - (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) - ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 - deep= - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) - ; full house ties with two sets - ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 - deep= - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) - ; full house beats flush - ; 51 52 53 41 42 > A1 Q1 T1 81 71 - deep> - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) - (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) - ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 - deep= - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) - (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) - ; higher flush beats lower flush - ; A1 61 51 41 31 > K1 Q1 J1 T1 81 - deep> - (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) - (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) - ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 - deep= - (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) - (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) - ; flush with higher second card wins - ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 - deep> - (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) - (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) - ; flush with higher third card wins - ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 - deep> - (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) - (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) - ; flush with higher fourth card wins - ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 - deep> - (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) - (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) - ; flush with higher fifth card wins - ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 - deep> - (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) - (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) - ; flushes of different suits tie - ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 - deep= - (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) - (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) - ; same flush with higher sixth card ties - ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 - deep= - (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) - (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) - ; flush beats straight - ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 - deep> - (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) - ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) - (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) - ; straight with higher kicker ties - ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) - ; straights of different suits tie - ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) - (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) - ; higher straight beats lower straight - ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 - deep> - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) - (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) - (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) - ; lower (2-6) straight beats ace to four straight - ; 61 52 43 34 21 > A1 52 43 34 21 - deep> - (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - ; A1 62 53 44 31 22 = 62 53 44 31 22 - deep= - (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) - (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) - ; ace to four straight with higher kicker ties - ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 - deep= - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) - ; ace to fours of different suits tie - ; A1 52 43 34 21 = A2 53 44 31 22 - deep= - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) - ; ace to four straight beats set - ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 - deep> - (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) - ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 - deep= - (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) - ; higher set wins - ; 71 72 73 34 21 > 51 52 53 A4 K1 - deep> - (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) - (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) - ; set with higher first kicker wins - ; 71 72 73 A1 22 > 71 72 73 K1 Q2 - deep> - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) - (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) - ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 - deep= - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) - ; set with higher second kicker wins - ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 - deep> - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) - ; set with higher third kicker ties - ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 - deep= - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) - (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) - ; set beats two pair - ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 - deep> - (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) - ; two pair with higher high pair wins - ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 - deep> - (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) - (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) - ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 - deep= - (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) - (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) - ; two pair with tied higher pair and higher lower pair wins - ; K1 K2 71 72 23 > K1 K2 63 64 A1 - deep> - (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) - (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) - ; two pair with higher kicker wins - ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 - deep> - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) - ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 - deep= - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) - ; two pair with higher second kicker ties - ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 - deep= - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) - (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) - ; two pair beats pair - ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 - deep> - (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) - (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) - ; higher pair wins - ; 71 72 53 44 31 > 61 62 A3 K4 Q1 - deep> - (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) - (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) - ; tied pair with higher first kicker wins - ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 - deep> - (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) - (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) - ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 - deep= - (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) - (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) - ; tied pair with higher second kicker wins - ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 - deep> - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) - (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) - ; tied pair with higher third kicker wins - ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 - deep> - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) - ; tied pair with higher fourth kicker ties - ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 - deep= - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) - (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) - ; pair beats high card - ; 21 22 33 44 51 > A1 Q2 J3 T4 91 - deep> - (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) - (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) - ; higher high card wins - ; A1 22 33 44 61 > K1 Q2 J3 T4 81 - deep> - (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) - (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) - ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 - deep= - (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) - (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) - ; higher second card wins - ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 - deep> - (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) - (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) - ; higher third card wins - ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 - deep> - (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) - (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) - ; higher fourth card wins - ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 - deep> - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) - (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) - ; higher fifth card wins - ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 - deep> - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) - ; higher sixth card ties - ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) - ; high cards of different suits ties - ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 - deep= - (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) - (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) - ) -) diff --git a/resources/tests/game-referee-after-cl21/test_library_basics.py b/resources/tests/game-referee-after-cl21/test_library_basics.py deleted file mode 100644 index 926ddde7a..000000000 --- a/resources/tests/game-referee-after-cl21/test_library_basics.py +++ /dev/null @@ -1,165 +0,0 @@ -import os -import pytest -import random -from itertools import permutations -from typing import List -#from hsms.streamables.program import Program -#from steprun import diag_run_clvm, compile_module_with_symbols -#from lib.program import Program -from pathlib import Path -from clvm_rs import Program -from lib.steprun import diag_run_clvm, compile_module_with_symbols -from clvm_tools_rs import get_version - -print(f"clvm_tools_rs version is {get_version()}") -#include_dirs = os.getcwd() -include_dirs = [Path(__file__).parent, Path(__file__).parent.parent / "lib"] -Program.set_run_unsafe_max_cost(11000000000) - -print(f"XXX: {include_dirs}") -compile_module_with_symbols(include_dirs, 'smoke_test_deep_compare.clsp') -compare_program = Program.from_bytes(bytes.fromhex(open('smoke_test_deep_compare.clvm.hex').read())) - -compile_module_with_symbols(include_dirs, 'smoke_test_sort.clsp') -sort_program = Program.from_bytes(bytes.fromhex(open('smoke_test_sort.clvm.hex').read())) - -compile_module_with_symbols(include_dirs, 'test_sort.clsp') -test_sort_program = Program.from_bytes(bytes.fromhex(open('test_sort.clvm.hex').read())) - -compile_module_with_symbols(include_dirs, 'test_permutations.clsp') -test_permutations_program = Program.from_bytes(bytes.fromhex(open('test_permutations.clvm.hex').read())) - -compile_module_with_symbols(include_dirs, 'test_reverse.clsp') -test_reverse_program = Program.from_bytes(bytes.fromhex(open('test_reverse.clvm.hex').read())) - -compile_module_with_symbols(include_dirs, 'test_prepend.clsp') -test_prepend_program = Program.from_bytes(bytes.fromhex(open('test_prepend.clvm.hex').read())) - -compile_module_with_symbols(include_dirs, 'test_range.clsp') -test_range_program = Program.from_bytes(bytes.fromhex(open('test_range.clvm.hex').read())) - -compile_module_with_symbols(include_dirs, 'smoke_test_permutations.clsp') -smoke_test_permutations_program = Program.from_bytes(bytes.fromhex(open('smoke_test_permutations.clvm.hex').read())) - -compile_module_with_symbols(include_dirs, 'test_handcalc.clsp') -test_handcalc_program = Program.from_bytes(bytes.fromhex(open('test_handcalc.clvm.hex').read())) - -def as_atom_list(prg: Program) -> List[bytes]: - """ - Pretend `prg` is a list of atoms. Return the corresponding - python list of atoms. - - At each step, we always assume a node to be an atom or a pair. - If the assumption is wrong, we exit early. This way we never fail - and always return SOMETHING. - """ - items = [] - obj = prg - while True: - pair = obj.pair - if pair is None: - break - atom = pair[0].atom - if atom is None: - break - items.append(atom) - obj = pair[1] - return items - -def test_smoke_compare(): - compare_program.run(Program.to([])) - -def test_handcalc(): - diag_run_clvm(test_handcalc_program, Program.to([]), 'test_handcalc.sym') - -def proper_list_inner(result,cl): - if hasattr(cl, 'pair') and cl.pair is not None: - result.append(cl.pair[0]) - return proper_list_inner(result,cl.pair[1]) - else: - return result - -def proper_list(cl): - result = [] - return proper_list_inner(result,cl) - -def int_list(cl): - return [Program.to(x).as_int() for x in as_atom_list(Program.to(cl))] - -def de_none_list(l): - return [x if x is not None else [] for x in l] - -def with_random_lists(n,f): - for length in range(n): # 0-10 length - for i in range(1 + (3 * length)): # A few orders each - orig_list = [random.randint(0,100) for x in range(length)] - f(orig_list) - -def test_prepend(): - for length1 in range(5): - list_1 = list(range(length1)) - for length2 in range(length1): - prepend_result = test_prepend_program.run([Program.to(list_1[:length2]),Program.to(list_1[length2:])]) - assert list_1 == int_list(prepend_result) - -def test_reverse(): - def test_reverse_list(l): - rev_args = Program.to([l]) - reversed_result = Program.to(list(reversed(l))) - reversed_by_prog = test_reverse_program.run(rev_args) - assert reversed_result == reversed_by_prog - - with_random_lists(10,test_reverse_list) - -def test_range(): - for length in range(10): - want_list = list(range(length)) - result = test_range_program.run(Program.to([length])) - assert want_list == result - -def do_test_permutations_of_size_n(n): - try_list = [random.randint(0,100) for x in range(n)] - want_set = list([list(v) for v in sorted(permutations(try_list))]) - listed_result = smoke_test_permutations_program.run(Program.to([try_list])) - pl = proper_list(listed_result) - perms_result = sorted([int_list(x) for x in de_none_list(pl)]) - assert want_set == perms_result - -def test_permutations_0(): - do_test_permutations_of_size_n(0) - -def test_permutations_1(): - do_test_permutations_of_size_n(1) - -def test_permutations_2(): - n = 2 - all_a_string = 0x616161616161 - all_b_string = 0x626262626262 - for try_list in [[all_a_string,all_b_string], [all_b_string,all_a_string]]: - want_set = list([list(v) for v in sorted(permutations(try_list))]) - listed_result = diag_run_clvm(smoke_test_permutations_program, Program.to([try_list]), 'smoke_test_permutations.sym') - pl = proper_list(listed_result) - perms_result = sorted([int_list(x) for x in de_none_list(pl)]) - assert want_set == perms_result - -def test_chialisp_sort_program(): - diag_run_clvm(test_sort_program, Program.to([]), 'test_sort.sym') - -def test_permutations_n(): - for i in range(3,6): - do_test_permutations_of_size_n(i) - -def test_chialisp_permutations_program(): - diag_run_clvm(test_permutations_program, Program.to([3, 5]), 'test_permutations.sym') - -def test_smoke_sort(): - for length in range(7): # 0-7 length - for i in range(1 + (3 * length)): # A few orders each - orig_list = [random.randint(0,100) for x in range(length)] - sort_args = Program.to([orig_list]) - sorted_list = Program.to(sorted(orig_list)) - sort_res = sort_program.run(sort_args) - assert sort_res == sorted_list - -if __name__ == '__main__': - test_smoke_sort() diff --git a/resources/tests/game-referee-after-cl21/test_permutations.clsp b/resources/tests/game-referee-after-cl21/test_permutations.clsp deleted file mode 100644 index d5b6d125f..000000000 --- a/resources/tests/game-referee-after-cl21/test_permutations.clsp +++ /dev/null @@ -1,63 +0,0 @@ -(mod (M N) - (include *standard-cl-21*) - (include prepend.clinc) - (include reverse.clinc) - (include map.clinc) - (include len.clinc) - (include range.clinc) - (include sort.clinc) - (include assert.clinc) - (include deep_compare.clinc) - (include permutations.clinc) - (include last.clinc) - (include busy.clinc) - (include all-in-list.clinc) - (include print.clinc) - - (defun ! (x) - (if x - (* x (! (- x 1))) - 1 - ) - ) - (defun no_repeats_inner ((first . remainder)) - (if remainder - (if (deep= first (f remainder)) - 0 - (no_repeats_inner remainder) - ) - 1 - ) - ) - (defun no_repeats (mylist) - (if mylist - (no_repeats_inner (sort (lambda (a b) (= (deep_compare a b) -1)) mylist)) - 1 - ) - ) - (assert - ;; Is permutations expected to collapse equal alternatives when two of - ;; the items to shuffle are equal? - (= (* (! M) 4) (len (permutations (c 0 (range M))))) - (busy - (lambda (listlen) - (assign - mylist (range listlen) - permed (permutations mylist) - (assert - (= (len permed) (! listlen)) - ;; ensure we didn't produce any permutations that have - ;; repeated elements in them, which would indicate that - ;; the permutation function misbehaved - (all-in-list (map (lambda (L) (no_repeats L)) permed)) - (no_repeats permed) - ) - ) - ) - (reverse (range N)) - 1 - ) - (deep= (permutations 0) (q ())) - 0 - ) -) diff --git a/resources/tests/game-referee-after-cl21/test_prepend.clsp b/resources/tests/game-referee-after-cl21/test_prepend.clsp deleted file mode 100644 index 9f0d45819..000000000 --- a/resources/tests/game-referee-after-cl21/test_prepend.clsp +++ /dev/null @@ -1,5 +0,0 @@ -(mod (X Y) - (include *standard-cl-21*) - (include prepend.clinc) - (prepend X Y) - ) diff --git a/resources/tests/game-referee-after-cl21/test_range.clsp b/resources/tests/game-referee-after-cl21/test_range.clsp deleted file mode 100644 index a7dc5edd9..000000000 --- a/resources/tests/game-referee-after-cl21/test_range.clsp +++ /dev/null @@ -1,6 +0,0 @@ -(mod (X) - (include *standard-cl-21*) - (include range.clinc) - - (range X) - ) diff --git a/resources/tests/game-referee-after-cl21/test_reverse.clsp b/resources/tests/game-referee-after-cl21/test_reverse.clsp deleted file mode 100644 index b1d843648..000000000 --- a/resources/tests/game-referee-after-cl21/test_reverse.clsp +++ /dev/null @@ -1,6 +0,0 @@ -(mod (X) - (include *standard-cl-21*) - (include reverse.clinc) - - (reverse X) - ) diff --git a/resources/tests/game-referee-after-cl21/test_sort.clsp b/resources/tests/game-referee-after-cl21/test_sort.clsp deleted file mode 100644 index 8185024d0..000000000 --- a/resources/tests/game-referee-after-cl21/test_sort.clsp +++ /dev/null @@ -1,37 +0,0 @@ - -(mod () - (include *standard-cl-21*) - (include print.clinc) - (include sort.clinc) - (include assert.clinc) - (include deep_compare.clinc) - (include reverse.clinc) - (include prepend.clinc) - (include map.clinc) - (include range.clinc) - (include permutations.clinc) - (include last.clinc) - (include busy.clinc) - - (defun try_list (mylist newlist) - (assert (deep= (print "sorted" (sort (lambda (A B) (deep< A B)) newlist)) mylist) 0) - ) - - (defun try_permuted_list (mylist) - (busy (lambda ((& mylist) newlist) (try_list mylist newlist)) - (print "sort all these" (permutations (print "mylist" mylist))) - 0 - ) - ) - (last - (try_list 0 0) - (try_list (range 15) (range 15)) - (try_list (range 15) (reverse (range 15))) - (try_permuted_list (list -1 -1 0 0 2)) - (busy (lambda (i) (try_permuted_list (print "sortme" (range i)))) - (range 4) - 0 - ) - 1 - ) -) diff --git a/resources/tests/game-referee-after-cl21/testnoncegame.py b/resources/tests/game-referee-after-cl21/testnoncegame.py deleted file mode 100644 index 3b4cd2c2a..000000000 --- a/resources/tests/game-referee-after-cl21/testnoncegame.py +++ /dev/null @@ -1,33 +0,0 @@ -import hashlib - -from hsms.streamables.program import Program - -from clvm.EvalError import EvalError - -noncegame = Program.from_bytes(bytes.fromhex(open("noncegame.clvm.hex").read())) -noncehash = noncegame.tree_hash() - -def drun(prog: Program, args: Program): - try: - return prog.run(args) - except EvalError as ee: - print(f"brun -x -y main.sym {prog} {Program.to(args)}") - raise - -def testnonce(startnonce, maxnonce): - for i in range(startnonce, maxnonce): - mygame = noncegame.curry(i, noncehash) - good_parameters = [i*2, noncegame.curry(i+1, noncehash).tree_hash(), 1, (i*4, b'g')] - bad_parameters = [i*3, noncegame.curry(i+2, noncehash).tree_hash(), 2, (i*5, b'g')] - assert drun(mygame, good_parameters) == b'g' - for j in range(len(good_parameters)): - try: - p = list(good_parameters) - p[j] = bad_parameters[j] - mygame.run(p) - assert False - except EvalError as ee: - pass - -if __name__ == '__main__': - testnonce(3, 7) diff --git a/resources/tests/game-referee-after-cl21/testreferee.py b/resources/tests/game-referee-after-cl21/testreferee.py deleted file mode 100644 index 01eb53643..000000000 --- a/resources/tests/game-referee-after-cl21/testreferee.py +++ /dev/null @@ -1,479 +0,0 @@ -import pytest -from hashlib import sha256 -from contextlib import asynccontextmanager -from chia.clvm.spend_sim import SimClient, SpendSim -from pathlib import Path -from clvm.casts import int_to_bytes, int_from_bytes - -from hsms.streamables.program import Program -from clvm_tools_rs import compile_clvm -from clvm_tools.binutils import disassemble - -from clvm.EvalError import EvalError -from chia.types.mempool_inclusion_status import MempoolInclusionStatus -from chia.util.errors import Err -from dataclasses import dataclass -from typing import Any -from chia_rs import Coin -from chia.types.spend_bundle import SpendBundle -from chia.types.coin_spend import CoinSpend -from blspy import G2Element - -from steprun import diag_run_clvm, compile_module_with_symbols - -compile_module_with_symbols(['.'],'referee.clsp') -referee = Program.from_bytes(bytes.fromhex(open("referee.clvm.hex").read())) -refhash = referee.tree_hash() -compile_module_with_symbols(['.'],'referee_accuse.clsp') -referee_accuse = Program.from_bytes(bytes.fromhex(open("referee_accuse.clvm.hex").read())) -refaccusehash = referee.tree_hash() -compile_clvm('rockpaperscissorsa.clsp', 'rockpaperscissorsa.clvm.hex', ['.']) -MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) -compile_clvm('rockpaperscissorsb.clsp', 'rockpaperscissorsb.clvm.hex', ['.']) -MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) -compile_clvm('rockpaperscissorsc.clsp', 'rockpaperscissorsc.clvm.hex', ['.']) -MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) -compile_clvm('rockpaperscissorsd.clsp', 'rockpaperscissorsd.clvm.hex', ['.']) -MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) - -move = 0 -accuse = 1 -timeout = 2 - -def drun(prog: Program, *args: Program): - try: - return prog.run(*args) - except EvalError as ee: - print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") - raise - -def sha(blob:bytes) -> bytes: - return sha256(blob).digest() - -@pytest.fixture(scope="function") -@asynccontextmanager -async def setup_sim() : - sim = await SpendSim.create(db_path=Path("file:db_test?mode=memory&cache=shared")) - sim_client = SimClient(sim) - await sim.farm_block() - - try: - yield sim, sim_client - finally: - await sim.close() - -def bootstrap_referee(parent_coin_id, initial_validation_program_hash, initial_split, - amount, timeout, max_move_size, mover_puzzle, waiter_puzzle): - """ - returns referee_wrap - """ - puzzle_hash = referee.curry( - [initial_validation_program_hash, 0, initial_split, amount, timeout, max_move_size, mover_puzzle.tree_hash(), - waiter_puzzle.tree_hash(), referee.tree_hash()]).tree_hash() - coin = Coin(parent_coin_id, puzzle_hash, amount) - return RefereeWrap(coin, bytes(32), bytes(32), bytes(32), - initial_validation_program_hash, 0, initial_split, timeout, max_move_size, - mover_puzzle, waiter_puzzle) - -@dataclass -class RefereeWrap: - coin: Any - grandparent_id: Any - parent_validation_program_hash: Any - parent_everything_else_hash: Any - validation_program_hash: Any - move: Any - split: Any - timeout: Any - max_move_size: Any - mover_puzzle: Any - waiter_puzzle: Any - - def curried_parameters_for_our_puzzle(self, purpose, for_self, move_to_make, split, validation_program_hash): - result = Program.to([ - validation_program_hash, - move_to_make, - split, - self.coin.amount, - self.timeout, - self.max_move_size, - self.mover_puzzle.tree_hash() if for_self else self.waiter_puzzle.tree_hash(), - self.waiter_puzzle.tree_hash() if for_self else self.mover_puzzle.tree_hash(), - refhash - ]) - print(f'for {purpose} curried_parameters_for_our_puzzle is {result}') - return result - - def get_puzzle(self): - return referee.curry(self.curried_parameters_for_our_puzzle( - "GET_PUZZLE", - True, - self.move, - self.split, - self.validation_program_hash - )) - - def SpendMove(self, password, move_to_make, split, validation_program_hash): - """ - returns (solution, new RefereeWrap) - """ - print(f"MOVE referee mover_puzzle {self.mover_puzzle.tree_hash()}") - print(f"MOVE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") - curried_parameters = self.curried_parameters_for_our_puzzle( - "SPEND_MOVE", - False, - move_to_make, - split, - validation_program_hash - ) - print(f"MOVE referee curried parameters {curried_parameters}") - new_puzzle_hash = referee.curry(curried_parameters).tree_hash() - print(f"MOVE new puzzle hash {Program.to(new_puzzle_hash)}") - solution = Program.to([move, move_to_make, split, validation_program_hash, self.mover_puzzle, - [password, [51, new_puzzle_hash, self.coin.amount]]]) - coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) - everything_else_hash = Program.to([self.move, self.split, self.coin.amount, self.timeout, - self.max_move_size, self.mover_puzzle.tree_hash(), self.waiter_puzzle.tree_hash(), - referee.tree_hash()]).tree_hash() - return (solution, RefereeWrap(coin, self.coin.parent_coin_info, self.validation_program_hash, everything_else_hash, - validation_program_hash, move_to_make, split, self.timeout, self.max_move_size, - self.waiter_puzzle, self.mover_puzzle)) - - def SpendAccuse(self, password): - """ - returns (solution, RefereeAccuse) - """ - print(f"ACCUSE starting with puzzle hash {Program.to(self.get_puzzle().tree_hash())}") - print(f"ACCUSE parent_id {Program.to(self.coin.parent_coin_info)}") - print(f"ACCUSE referee mover_puzzle {self.mover_puzzle.tree_hash()}") - print(f"ACCUSE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") - new_puzzle_hash = referee_accuse.curry([ - self.parent_validation_program_hash, - self.validation_program_hash, - self.move, - self.split, - self.coin.amount, - self.timeout, - self.waiter_puzzle.tree_hash(), - self.mover_puzzle.tree_hash() - ]).tree_hash() - solution = Program.to([accuse, self.grandparent_id, self.parent_validation_program_hash, - self.parent_everything_else_hash, self.mover_puzzle, [password, [51, new_puzzle_hash, self.coin.amount]]]) - coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) - return (solution, RefereeAccuseWrap(coin, self.parent_validation_program_hash, self.validation_program_hash, - self.move, self.split, self.timeout, self.waiter_puzzle.tree_hash(), - self.mover_puzzle.tree_hash())) - - def SpendTimeout(self): - """ - returns (solution, movercoinid, waitercoinid) - """ - movercoinid = Coin(self.coin.name(), self.mover_puzzle.tree_hash(), self.split).name() - waitercoinid = Coin(self.coin.name(), self.waiter_puzzle.tree_hash(), - self.coin.amount - self.split).name() - return (Program.to((timeout, 0)), movercoinid, waitercoinid) - -@dataclass -class RefereeAccuseWrap: - coin: Any - old_validation_puzzle_hash: Any - new_validation_puzzle_hash: Any - move: Any - split: Any - timeout: Any - accused_puzzle_hash: Any - accuser_puzzle_hash: Any - - def get_puzzle(self): - return referee_accuse.curry([self.old_validation_puzzle_hash, self.new_validation_puzzle_hash, - self.move, self.split, self.coin.amount, self.timeout, self.accused_puzzle_hash, - self.accuser_puzzle_hash]) - - def SpendTimeout(self): - """ - returns (solution, coinid) - """ - coin = Coin(self.coin.name(), self.accuser_puzzle_hash, self.coin.amount) - return (Program.to(0), coin.name()) - - def SpendDefend(self, validation_program_reveal, validation_program_solution): - """ - returns (solution, coinid) - """ - solution = Program.to([validation_program_reveal, validation_program_solution]) - coin = Coin(self.coin.name(), self.accused_puzzle_hash, self.coin.amount) - return (solution, coin.name()) - -@pytest.mark.asyncio -@pytest.mark.parametrize('amove', [0, 1, 2]) -@pytest.mark.parametrize('bmove', [0, 1, 2]) -async def test_rps(amove, bmove, setup_sim): - total = 100 - alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) - alice_preimage = int_to_bytes(60 + amove) - alice_image = sha(alice_preimage) - bob_preimage = int_to_bytes(60 + bmove) - bob_image = sha(bob_preimage) - alice_move = int_to_bytes(amove) - nil = Program.to(0) - - # (mod (password . conditions) (if (= password 'alice') conditions (x))) - alice_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0185616c69636580ffff0103ffff01ff088080ff0180')) - alice_puzzle_hash = alice_puzzle.tree_hash() - # (mod (password . conditions) (if (= password 'bob') conditions (x))) - bob_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0183626f6280ffff0103ffff01ff088080ff0180')) - bob_puzzle_hash = bob_puzzle.tree_hash() - - async with setup_sim as (sym, client): - acs = Program.to(1) - acs_hash = acs.tree_hash() - await sym.farm_block(acs_hash) - mycoin = (await client.get_coin_records_by_puzzle_hashes([acs_hash], include_spent_coins = False))[0].coin - # make a coin for a game - referee = bootstrap_referee(mycoin.name(), MOD_A.tree_hash(), 2, total, 1000, 50, alice_puzzle, bob_puzzle) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(mycoin, acs, Program.to([[51, referee.coin.puzzle_hash, - referee.coin.amount]]))], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - savepoint = sym.block_height - # Alice accuse Bob of cheating (negative test, should fail) - solution, accuse = referee.SpendAccuse('alice') - (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.ASSERT_MY_PARENT_ID_FAILED - # timeout too early fail - solution, alice_reward_id, bob_reward_id = referee.SpendTimeout() - spend = SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), solution)], G2Element()) - (status, err) = await client.push_tx(spend) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED - # timeout succeeds - sym.pass_time(2000) - await sym.farm_block() - (status, err) = await client.push_tx(spend) - assert status == MempoolInclusionStatus.SUCCESS - assert err is None - await sym.farm_block() - assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == 2 - assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == total - 2 - await sym.rewind(savepoint) - # Alice makes an illegally large move, fails - solution, ref2 = referee.SpendMove('alice', bytes(100), 0, bytes(32)) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.GENERATOR_RUNTIME_ERROR - # Alice makes move with negative split, fails - solution, ref2 = referee.SpendMove('alice', 'abc', -1, bytes(32)) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.GENERATOR_RUNTIME_ERROR - # Alice makes move with split greater than amount, fails - solution, ref2 = referee.SpendMove('alice', 'abc', referee.coin.amount + 1, bytes(32)) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.GENERATOR_RUNTIME_ERROR - # Alice move 1 commit to image - bpuz = MOD_B.curry(alice_image) - solution, ref2 = referee.SpendMove('alice', alice_image, 0, bpuz.tree_hash()) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - savepoint = sym.block_height - # Bob accuse Alice of cheating - solution, accuse = ref2.SpendAccuse('bob') - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - savepoint2 = sym.block_height - # Alice accusation defend, gets everything - solution, reward_id = accuse.SpendDefend(MOD_A, nil) - print(solution) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = - False) - reward_coin = reward_coin_wrapper[0].coin - assert reward_coin.amount == referee.coin.amount - assert reward_coin.puzzle_hash == alice_puzzle_hash - await sym.rewind(savepoint2) - # accusation timeout too early fail - solution, reward_id = accuse.SpendTimeout() - spend = SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), solution)], G2Element()) - (status, err) = await client.push_tx(spend) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED - # accusation timeout succeed, Bob gets everything - sym.pass_time(2000) - await sym.farm_block() - (status, err) = await client.push_tx(spend) - assert status == MempoolInclusionStatus.SUCCESS - assert err is None - await sym.farm_block() - reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = - False) - reward_coin = reward_coin_wrapper[0].coin - assert reward_coin.amount == referee.coin.amount - assert reward_coin.puzzle_hash == bob_puzzle_hash - await sym.rewind(savepoint) - # Bob move 2 commit to image - cpuz = MOD_C.curry([alice_image, bob_image]) - solution, ref3 = ref2.SpendMove('bob', bob_image, 0, cpuz.tree_hash()) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - savepoint = sym.block_height - # Alice accuse - solution, accuse = ref3.SpendAccuse('alice') - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Bob defends - solution, reward_id = accuse.SpendDefend(bpuz, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - reward_coin = (await client.get_coin_records_by_names([reward_id], include_spent_coins = - False))[0].coin - assert reward_coin.amount == referee.coin.amount - assert reward_coin.puzzle_hash == bob_puzzle_hash - await sym.rewind(savepoint) - # Alice reveals wrong preimage - alice_bad_preimage = int_to_bytes(61 + amove) - dpuz = MOD_D.curry([(amove + 1) % 3, bob_image]) - solution, ref4 = ref3.SpendMove('alice', alice_bad_preimage, 0, dpuz.tree_hash()) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Bob accuses - solution, accuse = ref4.SpendAccuse('bob') - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Alice defends, fails - solution, reward_id = accuse.SpendDefend(cpuz, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.GENERATOR_RUNTIME_ERROR - await sym.rewind(savepoint) - # Alice move 3 reveal preimage - dpuz = MOD_D.curry([alice_move, bob_image]) - solution, ref4 = ref3.SpendMove('alice', alice_preimage, 0, dpuz.tree_hash()) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - savepoint = sym.block_height - # Bob accuses - solution, accuse = ref4.SpendAccuse('bob') - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Alice defends - solution, reward_id = accuse.SpendDefend(cpuz, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.rewind(savepoint) - # Bob move 4 reveal wrong preimage - bob_bad_preimage = int_to_bytes(121 + amove) - solution, ref5 = ref4.SpendMove('bob', bob_bad_preimage, 0, dpuz.tree_hash()) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Alice accuses - solution, accuse = ref5.SpendAccuse('alice') - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Bob attempts defense, fails - solution, reward_id = accuse.SpendDefend(dpuz, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.GENERATOR_RUNTIME_ERROR - # Bob attempts defense with wrong validation program, fails - solution, reward_id = accuse.SpendDefend(acs, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.GENERATOR_RUNTIME_ERROR - await sym.rewind(savepoint) - if amove == bmove: - # Bob move 4 gives wrong split - solution, ref5 = ref4.SpendMove('bob', bob_preimage, 0, dpuz.tree_hash()) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Alice accuses - solution, accuse = ref5.SpendAccuse('alice') - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Bob attempts defense, fails - solution, reward_id = accuse.SpendDefend(dpuz, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.GENERATOR_RUNTIME_ERROR - await sym.rewind(savepoint) - # Bob move 4 reveal preimage - solution, ref5 = ref4.SpendMove('bob', bob_preimage, alice_final, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - savepoint = sym.block_height - # Alice attempts move, fails - solution, ref6 = ref5.SpendMove('alice', nil, 0, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.FAILED - assert err == Err.GENERATOR_RUNTIME_ERROR - # timeout, split correct - sym.pass_time(2000) - await sym.farm_block() - solution, alice_reward_id, bob_reward_id = ref5.SpendTimeout() - spend = SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), solution)], G2Element()) - (status, err) = await client.push_tx(spend) - assert status == MempoolInclusionStatus.SUCCESS - assert err is None - await sym.farm_block() - if alice_final != 0: - assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == alice_final - else: - assert len(await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False)) == 0 - if alice_final != ref5.coin.amount: - assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == ref5.coin.amount - alice_final - else: - assert len(await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False)) == 0 - await sym.rewind(savepoint) - # Alice accuses - solution, accuse = ref5.SpendAccuse('alice') - (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), - solution)], G2Element())) - assert status == MempoolInclusionStatus.SUCCESS - await sym.farm_block() - # Bob defends - solution, reward_id = accuse.SpendDefend(dpuz, nil) - (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), - solution)], G2Element())) - assert (status, err) == (MempoolInclusionStatus.SUCCESS, None) diff --git a/resources/tests/game-referee-after-cl21/testrockpaperscissors.py b/resources/tests/game-referee-after-cl21/testrockpaperscissors.py deleted file mode 100644 index ed45dbccc..000000000 --- a/resources/tests/game-referee-after-cl21/testrockpaperscissors.py +++ /dev/null @@ -1,48 +0,0 @@ -import hashlib - -from hsms.streamables.program import Program -from hsms.puzzles.load_clvm import load_clvm - -from clvm.EvalError import EvalError - - -MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) -MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) -MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) -MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) - - -def drun(prog: Program, *args: Program): - try: - return prog.run(*args) - except EvalError as ee: - print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") - raise - -def sha256(blob:bytes) -> bytes: - return hashlib.sha256(blob).digest() - -def testrps(amove, bmove): - total = 100 - alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) - alice_preimage = Program.to(60 + amove) - bob_preimage = Program.to(60 + bmove) - alice_image = sha256(alice_preimage.atom) - bob_image = sha256(bob_preimage.atom) - alice_move = Program.to(amove) - - cd = MOD_D.curry(alice_move, bob_image) - assert cd.run([total, bob_preimage, b'', alice_final, b'j']).atom == b'j' - cc = MOD_C.curry(alice_image, bob_image) - assert cc.run([total, alice_preimage, cd.tree_hash(), 0, b'j']).atom == b'j' - cb = MOD_B.curry(alice_image) - assert cb.run([total, bob_image, cc.tree_hash(), 0, b'j']).atom == b'j' - assert MOD_A.run([total, alice_image, cb.tree_hash(), 0, b'j']).atom == b'j' - -def testall(): - for i in range(3): - for j in range(3): - testrps(i, j) - -if __name__ == '__main__': - testall() diff --git a/resources/tests/lib/all-in-list.clinc b/resources/tests/game-referee-in-cl21/all-in-list.clinc similarity index 100% rename from resources/tests/lib/all-in-list.clinc rename to resources/tests/game-referee-in-cl21/all-in-list.clinc diff --git a/resources/tests/lib/assert.clinc b/resources/tests/game-referee-in-cl21/assert.clinc similarity index 100% rename from resources/tests/lib/assert.clinc rename to resources/tests/game-referee-in-cl21/assert.clinc diff --git a/resources/tests/lib/busy.clinc b/resources/tests/game-referee-in-cl21/busy.clinc similarity index 100% rename from resources/tests/lib/busy.clinc rename to resources/tests/game-referee-in-cl21/busy.clinc diff --git a/resources/tests/lib/condition_codes.clinc b/resources/tests/game-referee-in-cl21/condition_codes.clinc similarity index 100% rename from resources/tests/lib/condition_codes.clinc rename to resources/tests/game-referee-in-cl21/condition_codes.clinc diff --git a/resources/tests/lib/curry-and-treehash.clinc b/resources/tests/game-referee-in-cl21/curry-and-treehash.clinc similarity index 100% rename from resources/tests/lib/curry-and-treehash.clinc rename to resources/tests/game-referee-in-cl21/curry-and-treehash.clinc diff --git a/resources/tests/lib/curry.clinc b/resources/tests/game-referee-in-cl21/curry.clinc similarity index 100% rename from resources/tests/lib/curry.clinc rename to resources/tests/game-referee-in-cl21/curry.clinc diff --git a/resources/tests/lib/deep_compare.clinc b/resources/tests/game-referee-in-cl21/deep_compare.clinc similarity index 100% rename from resources/tests/lib/deep_compare.clinc rename to resources/tests/game-referee-in-cl21/deep_compare.clinc diff --git a/resources/tests/lib/filtermap.clinc b/resources/tests/game-referee-in-cl21/filtermap.clinc similarity index 100% rename from resources/tests/lib/filtermap.clinc rename to resources/tests/game-referee-in-cl21/filtermap.clinc diff --git a/resources/tests/lib/flatten.clinc b/resources/tests/game-referee-in-cl21/flatten.clinc similarity index 100% rename from resources/tests/lib/flatten.clinc rename to resources/tests/game-referee-in-cl21/flatten.clinc diff --git a/resources/tests/lib/last.clinc b/resources/tests/game-referee-in-cl21/last.clinc similarity index 100% rename from resources/tests/lib/last.clinc rename to resources/tests/game-referee-in-cl21/last.clinc diff --git a/resources/tests/lib/len.clinc b/resources/tests/game-referee-in-cl21/len.clinc similarity index 100% rename from resources/tests/lib/len.clinc rename to resources/tests/game-referee-in-cl21/len.clinc diff --git a/resources/tests/lib/map.clinc b/resources/tests/game-referee-in-cl21/map.clinc similarity index 100% rename from resources/tests/lib/map.clinc rename to resources/tests/game-referee-in-cl21/map.clinc diff --git a/resources/tests/lib/match.clinc b/resources/tests/game-referee-in-cl21/match.clinc similarity index 100% rename from resources/tests/lib/match.clinc rename to resources/tests/game-referee-in-cl21/match.clinc diff --git a/resources/tests/lib/max.clinc b/resources/tests/game-referee-in-cl21/max.clinc similarity index 100% rename from resources/tests/lib/max.clinc rename to resources/tests/game-referee-in-cl21/max.clinc diff --git a/resources/tests/lib/permutations.clinc b/resources/tests/game-referee-in-cl21/permutations.clinc similarity index 100% rename from resources/tests/lib/permutations.clinc rename to resources/tests/game-referee-in-cl21/permutations.clinc diff --git a/resources/tests/lib/prefix.clinc b/resources/tests/game-referee-in-cl21/prefix.clinc similarity index 100% rename from resources/tests/lib/prefix.clinc rename to resources/tests/game-referee-in-cl21/prefix.clinc diff --git a/resources/tests/lib/prepend.clinc b/resources/tests/game-referee-in-cl21/prepend.clinc similarity index 100% rename from resources/tests/lib/prepend.clinc rename to resources/tests/game-referee-in-cl21/prepend.clinc diff --git a/resources/tests/lib/print.clinc b/resources/tests/game-referee-in-cl21/print.clinc similarity index 100% rename from resources/tests/lib/print.clinc rename to resources/tests/game-referee-in-cl21/print.clinc diff --git a/resources/tests/lib/range.clinc b/resources/tests/game-referee-in-cl21/range.clinc similarity index 100% rename from resources/tests/lib/range.clinc rename to resources/tests/game-referee-in-cl21/range.clinc diff --git a/resources/tests/lib/reduce.clinc b/resources/tests/game-referee-in-cl21/reduce.clinc similarity index 100% rename from resources/tests/lib/reduce.clinc rename to resources/tests/game-referee-in-cl21/reduce.clinc diff --git a/resources/tests/lib/reverse.clinc b/resources/tests/game-referee-in-cl21/reverse.clinc similarity index 100% rename from resources/tests/lib/reverse.clinc rename to resources/tests/game-referee-in-cl21/reverse.clinc diff --git a/resources/tests/lib/shatree.clinc b/resources/tests/game-referee-in-cl21/shatree.clinc similarity index 100% rename from resources/tests/lib/shatree.clinc rename to resources/tests/game-referee-in-cl21/shatree.clinc diff --git a/resources/tests/lib/slice.clinc b/resources/tests/game-referee-in-cl21/slice.clinc similarity index 100% rename from resources/tests/lib/slice.clinc rename to resources/tests/game-referee-in-cl21/slice.clinc diff --git a/resources/tests/lib/sort.clinc b/resources/tests/game-referee-in-cl21/sort.clinc similarity index 100% rename from resources/tests/lib/sort.clinc rename to resources/tests/game-referee-in-cl21/sort.clinc diff --git a/resources/tests/lib/utils.clinc b/resources/tests/game-referee-in-cl21/utils.clinc similarity index 100% rename from resources/tests/lib/utils.clinc rename to resources/tests/game-referee-in-cl21/utils.clinc From 4a4667f3428aafe773c1c3ba05d0bc97cb4a9209 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 17 Aug 2023 20:22:51 -0700 Subject: [PATCH 110/196] Move compilations to reference so they can be checked --- .../tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex | 1 - .../tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex | 1 - resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex | 1 - resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex | 1 - resources/tests/game-referee-in-cl21/test_permutations.clvm.hex | 1 - resources/tests/game-referee-in-cl21/test_prepend.clvm.hex | 1 - resources/tests/game-referee-in-cl21/test_range.clvm.hex | 1 - resources/tests/game-referee-in-cl21/test_reverse.clvm.hex | 1 - resources/tests/game-referee-in-cl21/test_sort.clvm.hex | 1 - 9 files changed, 9 deletions(-) delete mode 100644 resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex delete mode 100644 resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex delete mode 100644 resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex delete mode 100644 resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex delete mode 100644 resources/tests/game-referee-in-cl21/test_permutations.clvm.hex delete mode 100644 resources/tests/game-referee-in-cl21/test_prepend.clvm.hex delete mode 100644 resources/tests/game-referee-in-cl21/test_range.clvm.hex delete mode 100644 resources/tests/game-referee-in-cl21/test_reverse.clvm.hex delete mode 100644 resources/tests/game-referee-in-cl21/test_sort.clvm.hex diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex deleted file mode 100644 index cb3eb0bf7..000000000 --- a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff0e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff01ffff80ff80ff8080ffff81ffff80ffff01ff0eff05ff04ff03ff028080ffff01ffff01ff0eff05ff04ff03ff0280ff8080ffff81ffff58ffff01ff028080ffff01ffff01ff0280ff5880ffff80ffff03ff0280ffff03ff028080ffff81ffffff03ff0180ffff03ff038080ffff01ffff03ff0380ffff03ff018080ffff81ffffff01ff0180ffff02ff018080ffff01ffff03ff0180ffff02ff028080ffff81ffffff02ff0280ffff03ff01808080ffff04ffff0180ff808080808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff02ff0cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff0cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff0cffff04ff02ffff04ff2bffff04ff5bff8080808080ff1380ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex deleted file mode 100644 index ad4e2fba6..000000000 --- a/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ff1effff04ff02ffff04ff05ff80808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff14ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff1effff04ff02ffff04ffff02ff14ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff1cffff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ffff04ff09ff0b80ff02ffff03ff05ffff01ff02ffff01ff02ff1cffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex deleted file mode 100644 index 476b5f74e..000000000 --- a/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ff12ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff3e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ffff04ffff01ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff10ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff18ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffff02ff18ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff2affff04ff02ffff04ffff06ff0180ffff04ffff02ff14ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff3affff04ff02ffff04ff03ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff3cffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ff16ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff16ffff04ff02ffff04ff80ffff04ff05ff8080808080ff15ff17ff0b80ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex deleted file mode 100644 index 441ac847b..000000000 --- a/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ff8200feffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff0180808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0104ffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff01808080808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff0108ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0108ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff010dffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff010effff010480ffff04ffff04ffff010dffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0105ffff010480ffff04ffff04ffff0104ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff0180808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0102ffff010380ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0106ffff010380ffff04ffff04ffff0106ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0106ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0109ffff010480ffff04ffff04ffff0108ffff010180ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0105ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff01808080808080ff808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080ffff04ffff01ffffffffffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff8200a0ffff04ff02ffff04ffff06ff0180ffff04ffff02ff40ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff010180ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ff0bffff01ff02ffff01ff02ff8200f0ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffffff02ff8200f0ffff04ff02ffff04ff80ffff04ff05ff8080808080ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200a8ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff8200e8ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff8200b8ffff04ff02ffff04ffff06ff0180ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ff8080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ff0bffff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff80808080808080ff0180ffff01ff02ffff01ff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff808080808080ff018080ff0180ff02ffff03ffff02ff44ffff04ff02ffff04ffff04ffff018c736c69636520696e70757473ffff04ffff01866e796c697374ffff04ff0bff80808080ffff04ffff20ff0b80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200f8ffff04ff02ffff04ffff06ff0580ffff04ffff11ff0bffff010180ff808080808080ff018080ff0180ffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff8200a4ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff8200a4ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200e4ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff8200acffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffff02ff8200b4ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ff02ffff03ffff20ff1780ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ff0bffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ffff05ff1780ffff04ffff06ff1780ff808080808080ff0180ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ff808080808080ff018080ff0180ff018080ff0180ffff02ff8200ecffff04ff02ffff04ff05ffff04ff13ffff04ff1bff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ffff03ffff09ff17ffff010480ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff018080ff0180ff018080ff0180ff02ff8200bcffff04ff02ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff05ff8080808080ffff01ff80ff8080808080ffffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff02ffff03ffff18ffff09ff17ffff010280ffff09ff2fffff010480ff0b80ffff01ff02ffff01ff0105ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff17ffff05ff058080ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ff17ffff04ff2fff80808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ffff11ff17ffff01018080ffff01ff02ffff01ff02ffff03ffff09ff2fffff010480ffff01ff02ffff01ff10ff17ffff010380ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff10ff2fffff010180ff80808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff0101ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff8200a2ffff04ff02ffff04ff05ffff04ffff09ff09ffff010e80ffff01ff80ff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff04ffff04ff17ff0b80ffff018080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff0180ffff01ff02ffff01ff02ff8200b2ffff04ff02ffff04ffff06ff0180ffff04ffff02ff52ffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff8080808080ff018080ff0180ff018080ff0180ffff04ffff04ff2dff1580ff0b80ff02ff52ffff04ff02ffff04ff05ffff04ff09ffff01ff808080808080ffffff02ff5affff04ff02ffff04ff03ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200aa80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ea80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ff808080808080ff131bffff02ff8200faffff04ff02ffff04ff03ffff04ffff02ff8200fcffff04ff02ffff04ffff02ff8200e8ffff04ff02ffff04ff17ffff04ff09ffff01ff808080808080ff80808080ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ba80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200e8ffff04ff02ffff04ff0bffff04ff09ffff01ff808080808080ff8080808080ff808080808080ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff8200f6ffff04ff02ffff04ff03ffff04ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff8200e6ffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200a680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bffff01808080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff11ffff04ffff0180ff808080808080ff8080808080ff8080808080ff018080ff0180ffff04ffff02ff8200e2ffff04ff02ffff04ff17ff80808080ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200b680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200f2ffff04ff02ffff04ff17ff80808080ff8080808080ff80808080808080ffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff09ff09ff1b80ffff01ff02ffff0113ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff56ffff04ff02ffff04ff03ffff04ffff02ff8200e2ffff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ff0bffff01ff02ffff01ff04ffff0109ffff04ff0bffff01808080ff0180ffff01ff02ffff01ff04ffff0106ffff02ff8200f8ffff04ff02ffff04ff15ffff04ffff0105ff808080808080ff018080ff0180ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff4effff04ff02ffff04ff03ffff04ffff02ffff03ff17ffff01ff02ffff01ff04ffff0105ffff04ff17ffff01808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff04ff4fffff04ff81afffff04ffff02ff8200e8ffff04ff02ffff04ff59ffff04ff2fffff01ff808080808080ff8080808080808080ffffff02ff8200aeffff04ff02ffff04ff03ffff04ffff02ffff03ffff09ff27ffff010180ffff01ff02ffff01ff04ffff0101ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0105ff808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ff27ffff010280ffff01ff02ffff01ff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0102ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0104ff808080808080ff0180ffff01ff02ffff01ff04ffff0103ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff27ffff010380ffff01ff02ffff01ff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0104ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff0180ffff01ff02ffff01ff04ffff0107ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff04ffff0108ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff8080808080ffff02ff5cffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ee80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ff29ffff04ff15ffff04ff0bff80808080ff8080808080ff02ff8200e0ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ff8200beffff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff15ff80808080ffff04ffff02ff4affff04ff02ffff04ff2dff80808080ff808080808080ffff02ffff03ffff02ff11ffff04ff0bffff04ff17ff80808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff0bffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff29ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff17ffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff59ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ff79ffff01ff02ffff01ff02ff5effff04ff02ffff04ff79ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff02ffff03ff03ffff01ff02ffff01ff02ff5effff04ff02ffff04ff03ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex deleted file mode 100644 index 9758d6fd7..000000000 --- a/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ffff03ffff09ffff12ffff02ff66ffff04ff02ffff04ff05ff80808080ffff010480ffff02ff48ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff04ffff0180ffff02ff58ffff04ff02ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff5affff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200fe80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff50ffff04ff02ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff80808080ffff04ffff0101ff808080808080ffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff0180ff80808080ffff04ffff01ff8080ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff04ffff01ffffffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff40ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff02ff60ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff60ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff70ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffffff02ffff03ff05ffff01ff02ffff01ff10ffff0101ffff02ff48ffff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff68ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffff02ff68ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff05ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffffffff02ff78ffff04ff02ffff04ff05ffff01ff80ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff44ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff6cffff04ff02ffff04ff03ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff54ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff7cffff04ff02ffff04ffff06ff0180ffff04ffff02ff5cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffffffff09ffff02ff5cffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff4affff04ff02ffff04ffff02ff40ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff62ffff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffff02ffff03ff05ffff01ff02ffff01ff02ff62ffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff6affff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff6affff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff5affff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff04ffff04ffff0101ffff05ff058080ffff02ff7affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffffff02ffff04ffff0122ffff02ff7affff04ff02ffff04ff05ff8080808080ff8080ff02ffff03ff05ffff01ff02ffff01ff12ff05ffff02ff66ffff04ff02ffff04ffff11ff05ffff010180ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffff02ffff03ff0dffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ff09ffff04ffff05ff0d80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff56ffff04ff02ffff04ff0dff80808080ff018080ff0180ff0180ffff01ff02ffff01ff0101ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff56ffff04ff02ffff04ffff02ff74ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ff80808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffffff09ffff02ff5cffff04ff02ffff04ff0bffff04ff17ff8080808080ffff0181ff80ff02ff5effff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ffff09ffff02ff48ffff04ff02ffff04ff0bff80808080ffff02ff66ffff04ff02ffff04ff29ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff46ffff04ff02ffff04ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200be80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff0bffff04ffff0180ff808080808080ff80808080ffff01ff02ffff01ff02ff76ffff04ff02ffff04ff0bff80808080ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff02ff76ffff04ff02ffff04ff0bff80808080ff02ff6effff04ff02ffff04ffff04ff80ffff04ff0bff808080ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex deleted file mode 100644 index 47dd7f1f1..000000000 --- a/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff02ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_range.clvm.hex b/resources/tests/game-referee-in-cl21/test_range.clvm.hex deleted file mode 100644 index 628a68fe6..000000000 --- a/resources/tests/game-referee-in-cl21/test_range.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff04ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex deleted file mode 100644 index 492966787..000000000 --- a/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ffff01ff02ff04ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_sort.clvm.hex b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex deleted file mode 100644 index 4cf09e661..000000000 --- a/resources/tests/game-referee-in-cl21/test_sort.clvm.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff4affff04ff02ffff04ffff0104ff80808080ffff04ffff0180ff808080808080ffff04ffff02ff6effff04ff02ffff04ffff04ffff0181ffffff04ffff0181ffffff04ffff0180ffff04ffff0180ffff04ffff0102ffff01808080808080ff80808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff7cffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff0180ffff04ffff0180ff8080808080ffff04ffff0101ffff0180808080808080ff80808080ffff04ffff01ffffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff50ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff50ffff04ff02ffff04ff05ffff01ff80ff8080808080ffffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0180ffff04ffff02ff70ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff24ffff04ff02ffff04ff03ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffffff02ff68ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff74ffff04ff02ffff04ffff06ff0180ffff04ffff02ff54ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ffff02ffff03ff0bffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff5cffff04ff02ffff04ff80ffff04ff05ff8080808080ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff22ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff52ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff72ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffffff02ff72ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff5affff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff52ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7a80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff46ffff04ff02ffff04ffff02ff22ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff6affff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffffff02ffff03ff05ffff01ff02ffff01ff02ff6affff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff66ffff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff56ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff02ff6cffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746564ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff0bff8080808080ff8080808080ffff04ff05ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffffff02ff4cffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff5e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff05ff808080ffff01ff01808080ff80808080ffff04ffff02ff20ffff04ff02ffff04ffff018e736f727420616c6c207468657365ffff04ffff02ff46ffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff01866d796c697374ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff808080808080ffff02ff76ffff04ff02ffff04ff09ffff04ff0bff8080808080ff02ff6effff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746d65ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ff80808080ff018080 From 3f4f0e1d7d1ad5eed924bba848d7af1055437180 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 17 Aug 2023 20:23:13 -0700 Subject: [PATCH 111/196] Move compilations to reference so they can be checked --- .../smoke_test_deep_compare.clvm.hex.reference | 1 + .../smoke_test_permutations.clvm.hex.reference | 1 + .../game-referee-in-cl21/smoke_test_sort.clvm.hex.reference | 1 + .../tests/game-referee-in-cl21/test_handcalc.clvm.hex.reference | 1 + .../game-referee-in-cl21/test_permutations.clvm.hex.reference | 1 + .../tests/game-referee-in-cl21/test_prepend.clvm.hex.reference | 1 + .../tests/game-referee-in-cl21/test_range.clvm.hex.reference | 1 + .../tests/game-referee-in-cl21/test_reverse.clvm.hex.reference | 1 + .../tests/game-referee-in-cl21/test_sort.clvm.hex.reference | 1 + 9 files changed, 9 insertions(+) create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex.reference create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex.reference create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex.reference create mode 100644 resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex.reference create mode 100644 resources/tests/game-referee-in-cl21/test_permutations.clvm.hex.reference create mode 100644 resources/tests/game-referee-in-cl21/test_prepend.clvm.hex.reference create mode 100644 resources/tests/game-referee-in-cl21/test_range.clvm.hex.reference create mode 100644 resources/tests/game-referee-in-cl21/test_reverse.clvm.hex.reference create mode 100644 resources/tests/game-referee-in-cl21/test_sort.clvm.hex.reference diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex.reference b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex.reference new file mode 100644 index 000000000..cb3eb0bf7 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff0e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff01ffff80ff80ff8080ffff81ffff80ffff01ff0eff05ff04ff03ff028080ffff01ffff01ff0eff05ff04ff03ff0280ff8080ffff81ffff58ffff01ff028080ffff01ffff01ff0280ff5880ffff80ffff03ff0280ffff03ff028080ffff81ffffff03ff0180ffff03ff038080ffff01ffff03ff0380ffff03ff018080ffff81ffffff01ff0180ffff02ff018080ffff01ffff03ff0180ffff02ff028080ffff81ffffff02ff0280ffff03ff01808080ffff04ffff0180ff808080808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff02ff0cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff0cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff0cffff04ff02ffff04ff2bffff04ff5bff8080808080ff1380ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex.reference b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex.reference new file mode 100644 index 000000000..ad4e2fba6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff1effff04ff02ffff04ff05ff80808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff14ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff1effff04ff02ffff04ffff02ff14ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff1cffff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ffff04ff09ff0b80ff02ffff03ff05ffff01ff02ffff01ff02ff1cffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex.reference b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex.reference new file mode 100644 index 000000000..476b5f74e --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff12ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff3e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ffff04ffff01ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff10ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff18ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffff02ff18ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff2affff04ff02ffff04ffff06ff0180ffff04ffff02ff14ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff3affff04ff02ffff04ff03ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff3cffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ff16ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff16ffff04ff02ffff04ff80ffff04ff05ff8080808080ff15ff17ff0b80ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex.reference new file mode 100644 index 000000000..441ac847b --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff8200feffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff0180808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0104ffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff01808080808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff0108ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0108ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff010dffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff010effff010480ffff04ffff04ffff010dffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0105ffff010480ffff04ffff04ffff0104ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff0180808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0102ffff010380ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0106ffff010380ffff04ffff04ffff0106ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0106ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0109ffff010480ffff04ffff04ffff0108ffff010180ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0105ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff01808080808080ff808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080ffff04ffff01ffffffffffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff8200a0ffff04ff02ffff04ffff06ff0180ffff04ffff02ff40ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff010180ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ff0bffff01ff02ffff01ff02ff8200f0ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffffff02ff8200f0ffff04ff02ffff04ff80ffff04ff05ff8080808080ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200a8ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff8200e8ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff8200b8ffff04ff02ffff04ffff06ff0180ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ff8080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ff0bffff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff80808080808080ff0180ffff01ff02ffff01ff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff808080808080ff018080ff0180ff02ffff03ffff02ff44ffff04ff02ffff04ffff04ffff018c736c69636520696e70757473ffff04ffff01866e796c697374ffff04ff0bff80808080ffff04ffff20ff0b80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200f8ffff04ff02ffff04ffff06ff0580ffff04ffff11ff0bffff010180ff808080808080ff018080ff0180ffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff8200a4ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff8200a4ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200e4ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff8200acffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffff02ff8200b4ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ff02ffff03ffff20ff1780ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ff0bffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ffff05ff1780ffff04ffff06ff1780ff808080808080ff0180ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ff808080808080ff018080ff0180ff018080ff0180ffff02ff8200ecffff04ff02ffff04ff05ffff04ff13ffff04ff1bff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ffff03ffff09ff17ffff010480ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff018080ff0180ff018080ff0180ff02ff8200bcffff04ff02ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff05ff8080808080ffff01ff80ff8080808080ffffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff02ffff03ffff18ffff09ff17ffff010280ffff09ff2fffff010480ff0b80ffff01ff02ffff01ff0105ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff17ffff05ff058080ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ff17ffff04ff2fff80808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ffff11ff17ffff01018080ffff01ff02ffff01ff02ffff03ffff09ff2fffff010480ffff01ff02ffff01ff10ff17ffff010380ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff10ff2fffff010180ff80808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff0101ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff8200a2ffff04ff02ffff04ff05ffff04ffff09ff09ffff010e80ffff01ff80ff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff04ffff04ff17ff0b80ffff018080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff0180ffff01ff02ffff01ff02ff8200b2ffff04ff02ffff04ffff06ff0180ffff04ffff02ff52ffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff8080808080ff018080ff0180ff018080ff0180ffff04ffff04ff2dff1580ff0b80ff02ff52ffff04ff02ffff04ff05ffff04ff09ffff01ff808080808080ffffff02ff5affff04ff02ffff04ff03ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200aa80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ea80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ff808080808080ff131bffff02ff8200faffff04ff02ffff04ff03ffff04ffff02ff8200fcffff04ff02ffff04ffff02ff8200e8ffff04ff02ffff04ff17ffff04ff09ffff01ff808080808080ff80808080ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ba80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200e8ffff04ff02ffff04ff0bffff04ff09ffff01ff808080808080ff8080808080ff808080808080ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff8200f6ffff04ff02ffff04ff03ffff04ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff8200e6ffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200a680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bffff01808080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff11ffff04ffff0180ff808080808080ff8080808080ff8080808080ff018080ff0180ffff04ffff02ff8200e2ffff04ff02ffff04ff17ff80808080ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200b680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200f2ffff04ff02ffff04ff17ff80808080ff8080808080ff80808080808080ffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff09ff09ff1b80ffff01ff02ffff0113ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff56ffff04ff02ffff04ff03ffff04ffff02ff8200e2ffff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ff0bffff01ff02ffff01ff04ffff0109ffff04ff0bffff01808080ff0180ffff01ff02ffff01ff04ffff0106ffff02ff8200f8ffff04ff02ffff04ff15ffff04ffff0105ff808080808080ff018080ff0180ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff4effff04ff02ffff04ff03ffff04ffff02ffff03ff17ffff01ff02ffff01ff04ffff0105ffff04ff17ffff01808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff04ff4fffff04ff81afffff04ffff02ff8200e8ffff04ff02ffff04ff59ffff04ff2fffff01ff808080808080ff8080808080808080ffffff02ff8200aeffff04ff02ffff04ff03ffff04ffff02ffff03ffff09ff27ffff010180ffff01ff02ffff01ff04ffff0101ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0105ff808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ff27ffff010280ffff01ff02ffff01ff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0102ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0104ff808080808080ff0180ffff01ff02ffff01ff04ffff0103ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff27ffff010380ffff01ff02ffff01ff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0104ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff0180ffff01ff02ffff01ff04ffff0107ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff04ffff0108ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff8080808080ffff02ff5cffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ee80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ff29ffff04ff15ffff04ff0bff80808080ff8080808080ff02ff8200e0ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ff8200beffff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff15ff80808080ffff04ffff02ff4affff04ff02ffff04ff2dff80808080ff808080808080ffff02ffff03ffff02ff11ffff04ff0bffff04ff17ff80808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff0bffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff29ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff17ffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff59ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ff79ffff01ff02ffff01ff02ff5effff04ff02ffff04ff79ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff02ffff03ff03ffff01ff02ffff01ff02ff5effff04ff02ffff04ff03ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex.reference new file mode 100644 index 000000000..9758d6fd7 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ffff03ffff09ffff12ffff02ff66ffff04ff02ffff04ff05ff80808080ffff010480ffff02ff48ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff04ffff0180ffff02ff58ffff04ff02ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff5affff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200fe80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff50ffff04ff02ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff80808080ffff04ffff0101ff808080808080ffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff0180ff80808080ffff04ffff01ff8080ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff04ffff01ffffffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff40ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff02ff60ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff60ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff70ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffffff02ffff03ff05ffff01ff02ffff01ff10ffff0101ffff02ff48ffff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff68ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffff02ff68ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff05ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffffffff02ff78ffff04ff02ffff04ff05ffff01ff80ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff44ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff6cffff04ff02ffff04ff03ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff54ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff7cffff04ff02ffff04ffff06ff0180ffff04ffff02ff5cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffffffff09ffff02ff5cffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff4affff04ff02ffff04ffff02ff40ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff62ffff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffff02ffff03ff05ffff01ff02ffff01ff02ff62ffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff6affff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff6affff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff5affff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff04ffff04ffff0101ffff05ff058080ffff02ff7affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffffff02ffff04ffff0122ffff02ff7affff04ff02ffff04ff05ff8080808080ff8080ff02ffff03ff05ffff01ff02ffff01ff12ff05ffff02ff66ffff04ff02ffff04ffff11ff05ffff010180ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffff02ffff03ff0dffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ff09ffff04ffff05ff0d80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff56ffff04ff02ffff04ff0dff80808080ff018080ff0180ff0180ffff01ff02ffff01ff0101ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff56ffff04ff02ffff04ffff02ff74ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ff80808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffffff09ffff02ff5cffff04ff02ffff04ff0bffff04ff17ff8080808080ffff0181ff80ff02ff5effff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ffff09ffff02ff48ffff04ff02ffff04ff0bff80808080ffff02ff66ffff04ff02ffff04ff29ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff46ffff04ff02ffff04ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200be80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff0bffff04ffff0180ff808080808080ff80808080ffff01ff02ffff01ff02ff76ffff04ff02ffff04ff0bff80808080ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff02ff76ffff04ff02ffff04ff0bff80808080ff02ff6effff04ff02ffff04ffff04ff80ffff04ff0bff808080ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex.reference new file mode 100644 index 000000000..47dd7f1f1 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff02ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_range.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_range.clvm.hex.reference new file mode 100644 index 000000000..628a68fe6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_range.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff04ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex.reference new file mode 100644 index 000000000..492966787 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ffff01ff02ff04ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_sort.clvm.hex.reference b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex.reference new file mode 100644 index 000000000..4cf09e661 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex.reference @@ -0,0 +1 @@ +ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff4affff04ff02ffff04ffff0104ff80808080ffff04ffff0180ff808080808080ffff04ffff02ff6effff04ff02ffff04ffff04ffff0181ffffff04ffff0181ffffff04ffff0180ffff04ffff0180ffff04ffff0102ffff01808080808080ff80808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff7cffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff0180ffff04ffff0180ff8080808080ffff04ffff0101ffff0180808080808080ff80808080ffff04ffff01ffffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff50ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff50ffff04ff02ffff04ff05ffff01ff80ff8080808080ffffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0180ffff04ffff02ff70ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff24ffff04ff02ffff04ff03ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffffff02ff68ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff74ffff04ff02ffff04ffff06ff0180ffff04ffff02ff54ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ffff02ffff03ff0bffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff5cffff04ff02ffff04ff80ffff04ff05ff8080808080ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff22ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff52ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff72ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffffff02ff72ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff5affff04ff02ffff04ffff06ff0180ffff04ffff05ff0b80ffff04ffff06ff0b80ff808080808080ff018080ff0180ffff02ff52ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7a80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff0bff808080ffff01ff01808080ff80808080ffff04ffff02ff46ffff04ff02ffff04ffff02ff22ffff04ff02ffff04ff09ffff04ff17ff8080808080ff80808080ffff04ffff02ff6affff04ff02ffff04ffff04ff0bff0980ffff04ff17ffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffffff02ffff03ff05ffff01ff02ffff01ff02ff6affff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff66ffff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff56ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff02ff6cffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746564ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff0bff8080808080ff8080808080ffff04ff05ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffffff02ff4cffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff5e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff05ff808080ffff01ff01808080ff80808080ffff04ffff02ff20ffff04ff02ffff04ffff018e736f727420616c6c207468657365ffff04ffff02ff46ffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff01866d796c697374ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff808080808080ffff02ff76ffff04ff02ffff04ff09ffff04ff0bff8080808080ff02ff6effff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746d65ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ff80808080ff018080 From 9b2dbc0243ba5e2fd3ae6c1237e44c03d8c546fb Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 00:22:28 -0700 Subject: [PATCH 112/196] Add some more, get the object cache off the ground --- wasm/src/api.rs | 44 +++--------------- wasm/src/mod.rs | 1 + .../clvm-tools-interface/src/lib/image.png | Bin 20753 -> 0 bytes .../clvm-tools-interface/src/lib/index.css | 20 -------- .../clvm-tools-interface/src/lib/index.ts | 14 ------ .../src/lib/tests/index.test.ts | 14 ------ 6 files changed, 7 insertions(+), 86 deletions(-) delete mode 100644 wasm/tests/clvm-tools-interface/src/lib/image.png delete mode 100644 wasm/tests/clvm-tools-interface/src/lib/index.css delete mode 100644 wasm/tests/clvm-tools-interface/src/lib/index.ts delete mode 100644 wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts diff --git a/wasm/src/api.rs b/wasm/src/api.rs index 506fbe0da..499085d0c 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -59,12 +59,9 @@ thread_local! { static REPLS: RefCell> = { return RefCell::new(HashMap::new()); }; - static OBJECTS: RefCell>> = { - return RefCell::new(HashMap::new()); - }; } -fn get_next_id() -> i32 { +pub fn get_next_id() -> i32 { NEXT_ID.with(|n| n.fetch_add(1, Ordering::SeqCst) as i32) } @@ -111,7 +108,7 @@ where result } -fn create_clvm_runner_err(error: String) -> JsValue { +pub fn create_clvm_runner_err(error: String) -> JsValue { let array = js_sys::Array::new(); array.set( 0, @@ -389,7 +386,7 @@ pub fn compose_run_function( }, Ok(x) => x, }; - + let function_path = match path_to_function(main_env.1.clone(), &hash_bytes.data().clone()) { Some(p) => p, _ => { @@ -497,37 +494,8 @@ pub fn sexp_to_string(v: &JsValue) -> JsValue { .unwrap_or_else(|| create_clvm_runner_err("unable to convert to value".to_string())) } -#[wasm_bindgen(inspectable)] -pub struct Program { - internal: i32 -} - #[wasm_bindgen] -impl Program { - #[wasm_bindgen(static_method_of = Program)] - pub fn to(input: &JsValue) -> Result { - let loc = Srcloc::start(&"*val*".to_string()); - let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| Err(create_clvm_runner_err(format!("unable to convert to value"))))?; - let new_id = get_next_id(); - let result = Program { internal: new_id }; - - OBJECTS.with(|objects| { - objects.replace_with(|objects| { - let mut work_objects = HashMap::new(); - swap(&mut work_objects, objects); - work_objects.insert(new_id, sexp); - work_objects - }) - }); - - Ok(result) - } - - #[wasm_bindgen(js_name = toString)] - pub fn to_string_impl(&self) -> String { - OBJECTS.with(|objects| { - let objects = objects.borrow(); - objects.get(&self.internal).map(|o| o.to_string()).unwrap_or_else(|| "".to_string()) - }) - } +pub fn h(v: String) -> Result, JsValue> { + let hex_data = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(v))).map_err(|_| js_sys::JsString::from("bad hex input"))?; + Ok(hex_data.data().clone()) } diff --git a/wasm/src/mod.rs b/wasm/src/mod.rs index cffabd1ef..04e57bbc2 100644 --- a/wasm/src/mod.rs +++ b/wasm/src/mod.rs @@ -1,2 +1,3 @@ pub mod api; mod jsval; +pub mod objects; diff --git a/wasm/tests/clvm-tools-interface/src/lib/image.png b/wasm/tests/clvm-tools-interface/src/lib/image.png deleted file mode 100644 index 83b0b67c5792eb30050f5d14237ded0387c505e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20753 zcmeFZXH-*N6gGJ2T|zHXReDzhsR^JU0)jvQ1wt2)F4DU+rCR_2X(BE3CcQV6F47?p zkX}MBfxujRXV#jTHEVv%pII~C_X7?jH~ZeR&pvza=h^$@tdqu==2UWmbw=}By`y5saSYyPezZ%fG$h@8tU`UZ}wk$#5L-CfuX1sI0WKVe|cZ#6WVqr_u?=N&cv7 zf9&$OYd;5l{xe70Ks(@=WNczkaWR|_7_Mk2tu=rj?wmYXZ)nM}PYpeiYqNez2%9i< zw?7;zt(OcH$&TeF<|v!-e{h&*Xl6S15;rzRHDQV{t+gj8tKAU0xD5QeSv7XkHnXtB z^Jr>a2<@-SU){FefG9++XJj0=HEWF)3u9X_%BB-qL)1P^_NnO#(C1MrDZf&X$j63o zk5VL(Zg=I?s3aew4asj0c7&DMoym_+*~|`Idd4{UdU~tuQ{6kgS^MoyUk81wMGE2# z6H}es`D5*mG2Crx!On6FZsgOsnDNmDOqguxj7s{^DF%94-ox3w-b!6(<%$OECI%)9 zFqbKr-_14bZt6GBo|5EOq77YIcYBewXzv03lPR4)qq+sR$f201){Dvd6*Z;d6>Wtl z0T;i$WP|*HXEU@xuT2+&^d}Bay+>T{5mH3clT!7^!P6QSJG9C+8lt#I-g--Tcihgt z{oA8ifLO6;i!>z9s;T^2iSL3#I`!kYAtDJ$QEq+|Cz`_e*|{^*Q5XdIJJ?C}j81+z z#h!D5Ry>Lp`2%%4K9Hlc`?C-6?w~Myc+FJWOb+XVt>@HN9JAMlXj z`D`L(3qLD{VH}yXRgk~7Xp<4VQK&u8DCMZeft>jPDb7#vv`^X~=)%PXi8@O%izIzYlMyH=Z2|6(WE zxft~dC$5}Wo^IjS>1mdK%+RJ279D=J(V)mAMjJ-lS?e&?ohi=m?qQ0_D4%`6DKBMd zO!-FTPmpZJN+d)OF-ceCLUGv=%{|$d#Cc?%7a#^$CUhK>qU*QrjuCh@TZp$0g?D&H zMrBdAxNoeU0^+0^yEo>mqq4rlbY{7lP+uz~HxJQl7@oV?X7%`6*Zz5qhbd>@sR?It z6^F}ik?GWYmAE>or~mj`Bt920pQP7CbfXLF;kba35$n;KSwN_b1<+YZFZ4Q&j3TO% zJ~>>TExu%liselrv(t8YerZIOyxck*8YP8^cap8zCetm_M`c^xgO!3@vXwUQLt6tSozGn!{PVny zPyYR=6V zz0VHUoW5f7X@Pf*yC2JbCHZU7c9iZkb?%dx>wN2$>lA$Ovqp@=Dv=lW>Dy1s=)CF! zJ7dZScTx@&;1%!uq8PRH%jpQJntu|i9#94K^l&FU*#$zY=!HVUU`yn^C)x{L;$txO zskR46z?+u24-KsR26(xYUy>NJ@x?Os_4JL|qi`8g_ksIKj0)#06hmg(T)|4@W?_ef zf@ls4v;5~&FFoyMweV*aPPv`}ENY>dn%+Cd!Z3#6>OS3-`SYfZyP!JAEP5}F6Q$Q2 z3>F`8U8%uwgwBpTMhr`M&7J;uMYTsLtzV6N5d{-C+x;52#i@CIlKwVxMc@c?;iG@4 zkI(h;)t><9UDoKqXl2racCS36=j3g~P8zeHJ_HJPt6L;-3=F9rFO@!6Q&Ubl%6)c& zHI0x{yH4*>X`2Qdcc&IZgU?k-+mqG0hAm?M7)^R}$0cZEdGi}Z@Y^Fh<|grNCVVFo zO6Q~gdF>QZ)kl7`1|fNh)C^vWH{A}0>V0q$;2cN;f|P-->FvN?#t-d4gnHGVZf?Tq zI-jjp1(esVZz2y!>60ngAD#TJW$@-OQP;t_KSx=l0&g5=o!;sRWkcTw!a&XIzceF6 zsFGGo>^Jq5GC>N%A*-&hos8o8B6S7w@Wl*xwl#K!h4zcD%=)h-=y;!D$8=ZY4}>ls z<n*Bnc2RYMAhV$Zs;m!(GM+ZeqNU{1gE?c z7}BGE<%r<5P0!4U#bLhhg_CfqUD{44%sU<>wv@>aT#zZwWSZPc`2(9z?wjgTC65t8 z_+0NP#-MqDT9{fFzky*Xmf*_#oSm21@0ZFICAYecRhbm<2+RI1WGF%jEE#luPF(8Z z!Mz2J(7U3@AVEBcj1KNj8YI;|l}h|!(pTXm5iGQ3e9X@(THW9J>x9ldVlqBDMVy}{ z!@!@e^3qT1nU8?`FRsFg{-tA^-Vn~beCAqtn`_^=9&4~v`@~DDYtM;wO(qkBexGs?2;sZggsfVMR{vUk^EU(3DgPL+PpKC+n!01RfwxS)7 zKZc3?Bj|WmdRc@XIW+S*_^~d{ajtqeNjG$S^a)^ZtchfAavuxItNT!!p|6SGF@&I zIv)4xq0_a|DZ`h1xjU(6-)#qDkb!x=7efI-2dPw03wl4hu2~xhJu*=7JY_Vemw;bg z+YH~#I|dFXp6@&QM(MdUNaS$M-x<{_AE=Jz2x>^>y6d9SNP&t}Jo`{w(DAb~W+k-K z0Y~j&>JlF^eA1Mlx7wN%0EQ`y#7C33%+NyogHWb0Z2hAr*?tA_6H1JDIt6w*V>`MI zA}WIFq}sYIG2<*Z8EqAsH$lzNK6kxWbw)+D*7+Xg&R4= z+8;fAP-%xZJljq2eT*AD?(J43w;0{pK1+mA*$n+<>sl)p)~+Dhn9Zj(`ndqP-gWO* zRQBZ{d?n1Jh}e&Ur*lJ*@Ug{hL(X_F8jBlfRH^FcA(ivM;bW~Y`vD>{qlBrq5VfaK z^^rVI0SoTvRE?9WX9a`x`_zx&@#$&W2`m?bd-)fJH5k2k(jY(<((3Q5EzfGm@cnam zW4_jCSmT-n8es+>Yu=6aaE_3r$)^a==6iOV#!(`y9857gwMI8%;e1}V6j#b@w1+-$ zgT6kmx3_Wl(K6Mp-seoeB78dF-F>9$&+IR}gfLT5jUOo7SEpQ&-M&D$n{KA(pU1}hc_NvW=ff<10CsOF)3y2{;DG z`--p#0|r)=$P5)GI%KHg-qf9(N7?qh!vx|%yA+e$jh+%+6q)HPVK98I8JOknd1fW& z>|`8a$isDa9b}pq)3e9oJlmR4_ICJOjLHSo>f8rx4Xy%4lSwn%XD<#5#WD^T2);*G z%u?J!ooWZ{R*59b{RxP|dA(%*QNkj9vq(AXcVD}2$)o5_h%V}UG7+orsS?ZAZbcq! zM5!Gpt);i5<8iQC*Ca%!WKn%)XL3%r&%#9AW$bSj6uj!H{x|O32av;9}JH?N5mUi9s5sy@wk9`?AVYpn}-o3-0U0Nd-sy8 zOPLVHVmK{ah`)dzNoRn^Q%D}8V6XdFc?RtcNxShz=40j63@iAZ>q^lT`v9f(7jghk zhu2bNRiDYf8@vZD(Y@1VAj?Oo_>IhGyZEp2oL?!G{U|J%{v}`){G~Im3I(|UUUj#L z!?2w9iMRBgGJeIk^Wx1xPy9NgrLRmz3c3owt@gV5EJBwuGW??4aoKDUTBN}b7lh&! zr_MT27vqL9lR$AkM&Oq1g6Z?UcSy+~8vLxkUMH ztoY%H9vvTCc^OCpREVQI_G^&AKwUwdd@csyx90>9qM`&E+$%pnQAOX(sHHU5tG$)l zcE5#Dls*nFNTRC{Xp}nU#-J0$^*rd>zv!iZ6=&b8U2M%D^h`abc;e&$&^TRbM1h}r z?|BQtNvKs`loyk~8PgRR)lx`w=2_xDFHN%JDZWsbvHrtD2)niW*Q+)2ubT@PQ9Zz% zZYhgk=k>kUa@|BPkT2-Q^TkHly5&v-%v_zi;vTT{X$w)*3rmV>KW2Hhxynzk4aa>L zc4sqjxDie{Kt-psY-Z0!%?YNV)?w`T4Kr{%~fmB-vFn|Ad>tA9=g44@D;;0jNuXjsViTo(;x0fJc{L%dvXQK9;|O&Z``m)=kS^eJan1q5Hg zb>cem__ANyn+6d6H2Lx9{+FE>-sq^dJo{_B92C&xVP5#5 z_H58oP>kkJ8}p)YV08%7QrNIGW@uZX0KDS!CoA5N4HFA`ztizM+y*5)ke2yz@vHO; zmtynR^l+FAQ9h48Xs#FPJD=#tf*&sTq5E$FrR z*UT2;d7U5nW!bZ8Mchf+IiVjTC@9@%CSbv}B=J~?#0eLO88d|Y zAY*Vz*zo6l|5dW$dxfSA5l2yu*Ocub?60$Q(huGa1qc--kY`C&(B=!J(TZT64XNME zd#YwX#%pSL8AkETlpWfGz&vGsx;>BkmSmdEH$jY*$R&MQMHLVFU0Fv4^!`kMc|~e^tzsPjn{^Ly*WL zp6NBAs<59GDQ6kZQubO;k58)zW4}LG@l?rk_1|~|^y2!F zFJ$4c;ha2s1KQZ`vOI;_F4cnoZN0u0wOi!oIs?3D(k$Mm}2=|nb_Byu|z zl$YVVeKr;e{ebhc(X#NFbU`1n_H_cxa*$3=g&-q-g*mq%?t`~X#(aL$y~tq3i6p`y z`I(`3qcLCkkizniR{^svBMLJM>>zp40<3S*%#l{*U$eOYF=8_5^X&K#xo=AnK(*d?#nb zT}B@m$cvZT7NhW6(CuqU{UusN`t)AmAc=~R@@M4y?)D)nk}MU9;nW=~1Kt$-pNqA^ z6u}+l|_|~W)!|;2-tneIs zJ1VyyqalRU?5N1biBmNEvKX{F17(%fa(c%%dhOH9Buber8?i|dc$9`Gd#8LJrkSN1 zzCorF8v!&nuxCd}tIC6PLDQ=_oZsJhY*!w$bUlYIr_@iU*m+&EdDHgj%l^az^wpD6 zm#$<2Z#MlwP!pO#KHdZJ5kc8%!(ixpcS%g(Dv^!;(L&L|rDYi@0{&ARwXF3sSrD77nHx`aFC&;QB!midz*rym~4rIacL?ZM< zc22qBiJ-cESpkjH-KfZbj7}1XBb+h_T|uV+4Ora`zX!AMKQ~*YCe(=o+N7rYyT&W_m5u`nZUNff6BSA-SX~2-@L8lM0WQ1quKW%z6vNQ#~DF zuq(IqBq*y~c(cJlbih0sn9O3AAeFUyIn4FdWcH_BL046_FsEIWs%vKjfm;jn;!9uCgE->P_! zQ1NXt{qG118*a%FcF2Q-ak2H z$3As4&^n41X7i&OYv*a)s24-RyPfbiWgDFe2JcP!vk0<`O1!c_Nr?S!tEYKg(`uIM87ZMoj7SCTL(-2AXO9ape~}kY(b+6L7RSxn$?yY)MOVsI zJr-*&f12#q>;Cca6B93+RS32xj_^UXUggInD0j3aoB(87LNWUGlsa#C`r3aPFt1|O3V5~v+{*V|bk1;7M zwkU)#SLwhHy@y=)a`w|AHpXvbBMtFo>?K}-TzqD+6nk5DiJkPamC~Ua@hX=(vEhz> z0cZX!dtUg6Tq`w?%tBqg@9wrp_Ek#xBuaA5aSrUcnm^>s ze%V%^{-VEmK#YwgX_ZK2Ji5p{eY>tTVP<;JPGz-_iQPU{8)7ogiaV~JGNy|=a1zp_ zlQnsG8Cl%5j$AtVpt7Uajo=J5zJO004swVkNjC&_w6@wlp83_Y7o2<`@{xJG#QLaS z=aJFgYuC8wGug;>Wb7nVMXb`1ESP@~Bu}glms~QC&OV1@-6Trce8XUQgIy$?fH^hK z-t(ybhXm;)N04VvrU`xsm;Y1LvtLXD9~XYbE#2d|m%nI2bz)goCYXHF-N<>w3#b+$ zv{vDyF-6`(1$fEx{q;^Xyl^ZpV^Mg z;hE>Iy)p>c@!c0boo9T+4qGGptl;3>3b`*1dlnX?(e#*$#ms=r9xjL@^7te2#7mF=bMs> zR0oIR<)7K{YS&e$$gtDfK2p7klU8;Nn^AE82a?h3QSh;JW5aanZ??=Ai2iJ%0#=HZ zI8zqK-s(Y0x5DjPAbRP!N9sGbEQFjvW06m8F6qwtF5VrRaXGJ8-_LJZB%%@zJt6Y9 z-83wR?uK_hGC}I3mQ<{*OLjb%T_>|wsV^|@d&hm`6U8(cAaa>%?4j>%1~NixeC$-byv&OTsy0W<(Vuh`FS+0k)C=K+#=hG>-ly#oTqDM= z=e%kORsAXCwr6an%wXo$rz%_deI?W!gWvqPr+rli|NH}w!KJ=0Q1P9^Z{c*EF7wRb zFo`;#9y6fWes$Jb)f;T?h$JQ>|NNr zS27?N6l^Jr{C!qDd0Y;VcCege_ZE4fkH?;Lu0q*&j1F}MzH&>p^>m9BHPV^fi+if9 zn?#_}JXy5i>lNSUxEvV5jP47-oGsNkUK3sZdn02pEssoTF9pQ1@89QFk_DUB4D;~| zQ=ipe9_$pzu7W(GcmXbloYXvUfwow`**j?=T)LAZxNzSBHvo< z?nyT*&oyIWRW?hv%&&ywbJf*RBu6TEZlAVq3cz8&J{<=CNa2xhKhfWvbhbUWn9*@; zYRtsb)>vj?cFa1aEPFNj;q!0q@ABn)T4V!SneyGf9u$J*^G{q?4-_vi|BT}(Q7yAS z&?{Up3oO@NIV+u*rTZHGMqc{=TQ5Mnr!N`R^bhX}>A!NgfN-qHzZfg zT*deKAwikQobF=`i19VR6cG$4FRJB*j}@=-YIkB|Je>${yi7~h?@2}>?K_l;=Wi7p zu}H+a|62pfPuOcOiC{5vPuBGd?Yqg-Zn8K}XXEF)w8Q|UdGtwl!cP8rh40eCc&|ATW=6AV%clTPE)SF@-4`ffZ%)*tpvD)2h=IP`0ylqP{6xarvt!Kdm^I9djF`=;M{C%1m$;i$0HGRr~x zwVp)xu4@iaH}Xl1PI4YkXL^lY%^KHVFE%Sn)n34 z^|Gz&%4L{bjr8c|7e@yNu936|?_6fG)?)I4huP#iSe+l1KPDU(!m1bFas+a-Ld$r8 z*VhydXOGpmbp){h9;KP-1aHXFypG8>d@mf43Gz8frd^8@UcpSN>zM6RiM7Gqx><+g zFPib|pKRO}XaJ>NWgZ>T*laxJTW|t<_BUQ9$D(cQ7cEHw>HX&FxzC6D7py4*W4tnN zo>fBexmMfrTTZraX|$uP>E!{(-}MjbIyu!^#SRZ#f25W607#4tpYeKw0g11p=Az05Wj0ZXR`~8w0 zoP`Mz(sodB5XC{qrq=4Rwl@EgEU0I|_RN{M`R2Augu@eM3-VWQLx1XQHk?kc<1W|v zkZAv%>p2n|Ds;Yhxe(qE1+c>au>xFA{!7vNL_zb-p^)&0HKLrd>qhydPXz4kNc9BA8Myc9=u~|No3CIFee280IB!I!gd-G z1n^rAq{YrL*|$jnEQIg);4ZiQU0l%K?Puf$KR>*U9XNhoE)Z>3+p`yH_<~=v9fXQY zThbRshbvxaNpkNizJ9}b8ibyyPZA-(0oT}rR-PND0&Ar~nK@{mLY^_h2mFHcdH$st zKa}nC*^>N95bJk;c%+GzTx-JQBjqmt{5HR~00NtlGpoR@3R}M*&EWT4_F{6h3c2s` zv-b52Buyu8c^w8pW%Hd4Ur7+m=zA z)T${UU&SEk9k^tMyMKtPZF-S6KpHYag08Q@?%3`@(Gdv_x^O+F19tq$@{d}I8maWJ zzSyVMhw*}i@3nfj-Ed+kgRrQBrq75bTm;P2rQ>qU?zzizhH-6a({8uE2TjA4jQPhb zh#Ybhp;Zx3t9dl$S&pI3krs8+W)3ikulg!!T)m*?AX$!L7Au}$_u^!YpvnwJi5Pp5R z@QeomRp%7uQoH!4MhnFCJYdQo=Y^BLpR0^ui>IO`SCPZ#l4Zi4hZQ3JF&kGH<1wcw z$hlR#qMDzMS&PwVbKjjCq;8p#C z@23Z4E!h(~yz&MGl0Pl(`%gxciwLAb4RgrMhi>_p1ZN{RWQ9+C?|m4V6b$BlRd*vmnK z2m+Iv-}W<|$e!O*NZG8siM_0*7>{1K>z2? zgq;ghgj(G9d&KQcKC>&w9oCSCh6sX^JD&dBS^2McSWM0pToV>u;yS_+nwbNKJN4Pw z)_Z@7YrGH%d$*|CYCCYhT*fZ-d8-bys3?w=C2IfS^X$$>=N3=N*SPo=?{Bhu!;529 z+VbcrtJpJKlThgM-)0xfAAZz^Ae>D9T;S!W<;kSCdy41YFPqx=G=C$&?|I133tLMu zif802!FB!^5OPg{);+jl$@JA{hTT`P@FFc5;+gTV>9cfLM`VB+Hy=LNvM3?-Ri*JS z1FR^VLq1zt=S0SL{p}OT!KofPWdK9D# z-GYl0rMeByUi*AD7sZARP9aDoEy09|iguu#K*TG>(W~`j;scj~^Rz!@J){wpurx@8 z3+d1{y1~$a6oX>_7Q9$r<~{jx^NrKsc;ek z+HEW})!W^@d86!jNPLq47>LwiMmz@Y^C@Fepcfl1hM0i9qRP4UY(YCV;u1z=@;EK4 zT>j?9s6oNY7uTQTB_!gKg8D^Khpp0XcQBjV*k06q)mG}xq~Rg~DQVlqq($rAkHSPZ zuY)GMzuS6l@NG5Pm5ZD}WICTEEd{!X3&^)`ae90`d$|i(FuHTe2ya*|q z;(bSx=q3etKL+2;uw3(l6+N@+Ry^WW>!ybm*E&ouC%F`Jb2X9oJoz%hx*R`KFKh7k zcN7uA4!DJh{J?IpBM)lj!=ZPV_NPp3K>Zzg+ih$sEJ0jzzNRW*#H*u;G<-gi5cWz` zm}us>P)${@c6FTZV$V1gNx@_g^Ky;g=_v6;S|rK;%+OzOff(&?hAUG z@Vw#HfEkC)gKKtmRO0tmw8GcAA8m$ysHDw1E;Qf8cULouXNpKLfO~xD?cFf8%WD>E zUlc7OOwELlgSdlhq=M}ZLyR>zMM3?7rtJnHZu(?hRNyjl|_;u#zG}9t<#lOs^0SP%x^_HFrBW+g9WdlGXP;q06l^GSkJAG?UP* zqK^r`1>AUx_TIU!oFzl5*Ls8-xnw=x2aLqMNQ2%Ry-hR}I2;2!>sLlF(YL4g$M*ZV zi}@c>hEwwdKF)hRB8Lb05e8YkA{wu?#dPS`EJ3kmd4YJ8YNVXbFH(D$E(jUHCCD7w z@BgA%5nYx|pWU8R7xV7)86r!ES@kOPB!$`|T2v+nH*UJL4Sm1N}xE!#sxI#5)#WEnfQgtDCkO0vLR97 zu9}^;!JFyvaOezEuEcgQ!x$iixVN3si+-_o@;WBaOasXyhrBNfQJG(SE8VFpF3Shp z(6CUS918e5e+3c8l{vE@ufxTK!z=-7jLzm^&blpN>HV&=B6Y&_vPFoQ5vP22>~^^V zD8x#Dxf`sN*FXT=Y>@AN^h+JVT_pAt*UA!Z0a$PNQwEm0q&_c0Ks$d)4qUw6#vc2O zc=L*eJ~NVlY1YIHKRmfc&rIIg2WkPaN_B9ZI?zg=Y(G)0k6NX}-5>0cxP!!2{H5SB z&h8y5>yFB7rf8vmzDgW40gVeZOU3Y(IE)kp^}H7$0HLPdmtN6l7TMxWF;}ErqPPXV z0jb)fVp8&UZPI$pQ~d7+qyg9T;U0RMyH#f0LpuyFCt5LEUT#=R^rt&y9KPxdI{Csx zIYw8_bzwKNZ}1CKQD}5U%nHlKcu-pykk%;gSk*JZ3!_*cwuUmjQ7~O(zhAk3J|y0}5w@NYP6xX4 z&nN2fpc{rEOIkvKF|bN|)T>4(znxTm;4M}+R;zYlyBz=s{rh_^xxXJb}U zKGJOElsh~@%#?)vENv)tK_Ue`ToUb%M=unM7@E8gf`r{1%vW@YkbMYrJ3fc41H2& zZ0x0{(fHwSub`}uJK*(GV5v5tCtJ(tJ%j&(JAwp!>0=+gI5_;DyW#%_?ce@C9trq= zLkY7yyKCu1$o0BVs{Sc^IeL&qX>PD*jl=^NDa$-5_-dqo3=o2Y&OJN`IKbu!Vc-CS z(*gg#d9(4BeDgnl;qklu>c9zqJUJIQ{7)rhfF-1j^P6Xq+O|lf?5Fmmxex79 zlmlP)C*{M3O1D5F*61J|721OSV7ypyIQP}>L!8q+M!!csm6}`raJYu&jENT3Ih6t( zl9zlw8Hb-$e>uWLkZZ#iCY)Z3Tz5UOPkml8ykY}(&Cqvd?NrS?aJx*+E1d8fZYYhf zA5NJr0rN!T4bG|jDOr@{z~Jxeh7*V9(EAk9Yx3iX;Hvjxcu+%g5BD-+&{{pc2F$-> zJ>s2AC+36XWOr7+J9cROwR#;~Z+zTnFX~T{s=jA6^MkfL&;GIWRW40>;FBMJ7~Zv; zmuLSia`BGVi5_mJF2f;}H%zq;Y=N^nquA}D2A)P|n$0U8@@ASYy+LbTi@-?DM|(8= zAUe2dg4v3P!`gsX(**p1{AFEY#)=7}GP>}wL$Et8UFzWJ5K?Tk#T8GSblzP&&=Z#$ zom3gth?F3GxlhyJCEv0#*bO0N4o0NHdWS9Y6SBNktWu`7brQ$MLeDyg+J?c59~vl4 zgU`T=@^9*_2!C8sj9o+qn{)Z5;WLg}aO(sq`<#s{PB51uk7Pfz?~??3lr$(Ub>xa$ zJpE)vkuKAMWmRE-P^y(#{aO5BQAWKu$WFer2B=r& zOE-da!K-0qcshp*k-OcGS^L#UgO(+J1wBVL1I+JF=5DRo^3A8JYvTnAvg~6fPzpsL#>8HK{f%Pfs9ktd!ze z`p6HQu4Ovh0y`&A_a3~uIaq>q{)J?fqLeDwkfqd`T$=RCDc$gy1?1U-@?^dVflZi4 z0fftz&BwbJMjo}+hA!Vx-t2d)CR44n+_A+rgT6ANT6b8{oCxy)w!jV&H)a}y7WS=K z|H|&Cz`zst@_|4z934Ss=x+4yuef`nIVjmBE61qIaktb??Py$pdQhC?iT9-gbHacO20^;RgJ)LsiR zxnq6y;k>~LrO~E5eKyiiN?m(0C)KJV$Cv+fk%M*##0k+G^I(rib#WKD*MK5ezPUP- z5aTt$_v@G}xXTkvr>eCM)r+ka{{~a3o?LUkfs!yaEPnn?l3glKiy;#MOQ7X^2j$F3uKT+e zQrrnv6xUylprA~@C`k9lZRl1LCk>w~G{^FbO+KPD8V3t(M|G_$V>9L^TOQ@zZXAaO zV8`iqd=5@vufj#wEc_(Jw@2doXPgM~13a^HGjDA^mz?zWm<>=}jV#=G#!JjpyrF4V zpsa^}?6HA@x&NZ=*%8>~>FU$$)9iq;WeK$ON3;N~?}95|4>**}JLytO#ElxZSSJ z0I@FE0N!ket!GMkNl+h4M!7|z$N|c(ZL&0hTg;{E^Qg54XeII7LS#^nKAuuW!?j@E zbm3{?>kA9h!nkK^c2g72rVkA6*>;cv!|&AbAmZsy|GV`0)unSv``ikR9z{V5zsmex z&Xhi+Qw6dpoJBj%`@tG?9y#gWs15MSC3@s9e%2J5ONEQ{`*D}9B=sDl#rxu31VFIQ zXxsH=TaF1jWH8rFQz965mYsXYr{A|yqm7UIv>b!$_~u)TrGY4aB?2x6hM!BRzZccQ zA=P&(uzb~lZ$$XUzk>Jp^#C|<&>GdG^t4QT$T{#n5d-kEw0n(3-yuBpiC4fAVNP*r04ZsX3U7x|tZ} z7O-mZ0~4W%yubqxuM{8i&dC(MmI~CaxF2wDP#=Cs0qRix`7W{bPdpZJ`cZ?+m^C6o z0$25+v^uk=cY*S_ZyV^^$41Wn!lKfOvzBWIlTm5<>9UHE&_K~6W%-dWDaS7asm&{| zEF|dw|MmGHJ0Q}#Mxo3F{IS6rT?R_*etDjG^H;i*o@FD%?{brM84-#Ycm`Su6U4f7 zg2#NHo#~?8Ps7rp7a3Clsn=_n^!pk?i_I9Rym+pOaGf%)V&TB##)}_H;q7& z{>a8bYW}NicJP#P4y`3@ka>3n_$wPO4{__=*4`Di= zyt9#eB-3ezheMwbF!8izk+kE!p4`M{--Zw5eLj~fwoM2I>u*dX`Cu}f$UJH z12?{GoncK&3PcM%4wWsDEf%);VM}@VIPEX7UYggxCrHQ^?QJUydz8i4{32%QGb)ZT zAlQIbgh1|&eVB`I638>`b;DR#SNXVqXpr&coe7fQ(oo*Tx(h8IvsN z%YSBRqrS*CtjYnm?^IOs5#RTSOe&1E7=@RT1 zkvBB9YT=tJ3D>Ycar}YT_IEu~ag~S=w=N5Ok(=R7)a|8P-_B@R&G`HUtJXmcV>;^Q zv37V_fhT@j!z{BDyi{RL7D)XlI8@n_$)t6TfBlSmbMxdYYe!}}oiA-{QIPN@ewK!l z;`OuA1fuWijAKx%*FLM-6L`a4IiRW`F8$x6M#p8Zg**#~jzq0<0>o=85S42pY-C4vnl@xj0M3{|RJqb%pD{7=|i<1NLGwerul z1o4chV!k~2?7yECsYfyzO0{cCeikBxgE-;KU4;T^3zbc7Q|D{D+M|;BwzGWPpQa5K zuGw0!IgShm<|x~>bZWdPmBQAKk1O~nI2o|Shoj{z@`ZcTbe;9v96!56S}k}eHx@YMqMIw+cGdiX{&YhG%PSuaE|PrDpp?pG)*Ai2p^yw_ zykxX_o(}7c79OT$Czf(Giy}o@a_|X{OU^F@$$#Xfb``c2?lIA!KcK`ym;8+*q%b2p zt(;pYQ>d9Q@Hg&z#P!d=8|-bwmF5RGYYO)o;6~HqA6KyzQ&>zHnojVAK>_PFBky3( z39|r`91-mozsi^(ukt4VJNO-Qo`5;>zV>Ui_v!~tO&)pnSBe3*X|R8_o)H_^lTy(; zT4FMdaHDDuzW@5VUxI)Qr=#$*-~+)#1UOQ<@yA^se8d)hDfTi4&oWa`3s;)_7ff$7 z6T;l4lFhS%EGV}}%5ORTy7e)Zlv~e44f|xw6tK2iU|%WF%7wHg{Qb|~HauLI0RU2T z^}PVJYw|#pR?}mUw zY^dM)RwQ0W-oMyHfrR=QKyR7=_lyN2hdKUvF(y8IH5QkDp-ADiJ|Z zTl4SwII7jXtr%RHo3uyUa747w`8?3qK*+{3@=&IuT3v;0OJCCrGr84onA;&rO z`R8+v0Y9@V>@6OR=xqZJfCIzO|8GEZXLRID~y>2wgS z`=L(fm{9IuMSxy6J*U3TEdjePC{`Wg_U!UkX6Ec9~yz7!BK-5Fzv#pBV^(04p z@S7J%vw(TgqDNWs#idsv=wq2{lk&-(AweRe`}22Jp(va+*lFU%<5)n9Z+;sO0^{yr zpKv`+tQP$jWIpD%h#6%|&Nnd%x?u~jPc`mgA|4s77zH1Kk3+sd;rfiJ=%3h3ox3|j zwMS4C`y(1f7e!A@y)a5`e)jA#aK~Sukui%dFBq?X3Z2>V)fYQ;s_CEV`FZ!AwYaBz zYz^pFH3|FF>RhRMt)8I+&l$#QIWa32QxlwrcVqnr?wpfhiUdX1QsF1F3Ohf9nk|9x z`81-o&+K)VKkMV3Q&YV#^TQphExODI!^xOx@Ut#T3~_gOv-*06(9?mkBTOy+_J?h@ zfv-w24$KWYZn7FDbk6V3$C43G70$iNO!gHRSmn?MSPUGBTgKG*#(-6!L*q1LS*E8w zK{MgP)y4+N2vu?iORbP;4>#c@NpNo4}NT6JXQy`snOX#@0b5Y%-lGaaa&hY9V2hk2+uWh3P)x( zUoNNC3ujUW-8?TTzg0zh0rcMo2*t%OajQ0T(%#d{BmK^)|6-7RxRulom7pRtwF&>h z;ES2#mE(&(cn&hthg@1o`R;H&^em@?Gnj=GoX9FBU~QnM8cfNM!N2V9*z-#k5FwCT zr`zDZM6EyXF77BNnx}3%0Qp++od2*Xo(e58XgVz4;%$<8B;Z2}Zo*;V9Iuqtr(o?y zA1`Gz}~GZ)#!*+V&ZIhop+`#aZz{*MHbU`V2Ul6by2g%PRm+| zKJXp*&0V)^T!=Ss(ua% z2er`KC83G#3M3 zbN#Z(S3!@yeFMq2=<1w`cJ0`vZ}-UJG%?Pk?H)0pynW8nt;P z7c35=*Hy%_F2dVN256f_!^Brx{D$D1XTvf95#OgB$}-Qfj-y8G!B=Y^PMRG`COnsV zg`C-#nuGV~I(`LR&KIqGvvz09;aXK$iAm=(Hbh*+(@Afw*_!AAlp$4jVR*{_`Q+@) z;o^TLwns0>w2dv%Qdh}xomI)?=Y{~oJfH`|Qw~ZIzmc)se}z`b`ORd)U?C7vVD&xd z3nAIEJTcL>7gGQ0d)$N#Te!iCVzgex(JN6Ro~l5oG(QQ(5cGA^*@#O&gG>MarI{;#YU+x@2@RM4 z3KTFX4oi`>Y>{0kNh8Q0L9r|W3?S1|j0h3KW(X#bYI5qCRDJ}!6)$q1DEt-=sF|ug3 zEE+B}+UzSDi1Wny;^Cshqfv=doR!TcNP%sO*ei3wZm=kNb^s4K-we|k@|%jeh$YWuG(!oI-)xH4!Zeb6=r*eq`8G1wB^7OxZ%e0omufD&2_jc$nXJSaN-J z#`{e0mTtLf*Wx&B-xh9GBZd+uT1Fso6zFv#Vbsm~WC+y99((GC1!{G=K1RNs?VW^U z>hzjKqyAoy00^lB1Xyb84v~sYaJZ}cf{R6uInuO6GxSmkGra5Mv5ojPMRIS=!0<7B3jVQ9sdf4um0TOM6;t|xvQEz> z+8zFs_u_e<#aAXDM|9#Z)yGo<%^aA<5e!6LsAl#ubn?ubmt>2i|D%FW^G3JckURPjaE;e^~)c|X(v$W0BT4Ae+LLrll) zLKyN2(_et>OsRi%u(|@k^@~tUCH37!FV})G_R>-!Nj_D#R@*Oiw`~?bCDMLb?B2qM z0kUUYv*?E$c)%BE#B`?UeV0ooH}W#zDeMC;E2qVi&p8J9nDnhNi6h;c!pDB(;#{eQP)Ih-^qCIS=6NHQlG! zRXsMehTAH!bmr|!?_{m5PIo+dx-vyxlBb4Z43YMZ&mLVPV2ZnT)c_=KXc&H*cu17c?roeG!DZ67Md>Du%5ao?ayghxr z?l6f|^Ij6W{mXP#hP5~i0)G031r?w@({4_oolb$bTqhZGN9C(sflVJ#I`;`(wACZr zE`w{yaJ_-6^*Pn;%r(wV?XP4^yECI>M;>xE(o$q9KHO^; zbtjm4jddw{MsL~ot6Kd5;^SQoy1BPe5|7g#nn7GgPjNJ(=A%-9*NG0J80Mm-SLrJ} zecd@*&7f|`Y907*bBzUU2jPFEfo|bqsZ zX{^B@qbfa64YS4koT`ARO;S)3KnSLKkI$dyayLE$qI^7{(<;oJRQP+)9 zX^t4nd?}=%)BdSr_Xv!-KZ2|bhR1kK2;&#nhiFo>J1D-5>YN#&xW%J13$M7GJG+lv zs~yrPc+4YFscW|p{D4;*$#vsWidt~V5uwQM6K^ud#0qwcZz;56Er_NYqFEy89WpNz zFPrs!vR)rA_ZNx$Vo;RIoWUQMTHVxU4=`ZQrr{`N1P@uB_z diff --git a/wasm/tests/clvm-tools-interface/src/lib/index.css b/wasm/tests/clvm-tools-interface/src/lib/index.css deleted file mode 100644 index 55c846f49..000000000 --- a/wasm/tests/clvm-tools-interface/src/lib/index.css +++ /dev/null @@ -1,20 +0,0 @@ -html, -body { - margin: 0; - padding: 0; - font-family: sans-serif; - height: 100%; -} - -h1 { - margin: 0; - font-weight: 300; -} - -body { - background: url("image.png") no-repeat 98% 2%; - background-size: 300px; - padding: 20px; - height: 100%; - box-sizing: border-box; -} diff --git a/wasm/tests/clvm-tools-interface/src/lib/index.ts b/wasm/tests/clvm-tools-interface/src/lib/index.ts deleted file mode 100644 index 0225e997d..000000000 --- a/wasm/tests/clvm-tools-interface/src/lib/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import "./index.css"; - -class MyLibrary { - constructor() { - console.log("Library constructor loaded"); - } - - myMethod = (): boolean => { - console.log("Library method fired"); - return true; - }; -} - -export default MyLibrary; diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts deleted file mode 100644 index 7776cfc94..000000000 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import MyLibrary from '../index'; -import * as bls_loader from 'bls-signatures'; -var clvm_tools_rs = require('../../../../../pkg/clvm_tools_wasm'); - -it('Runs without crashing', () => { - new MyLibrary(); -}); - -it('Has BLS signatures support', async () => { - let bls = await bls_loader.default(); - let g1element = new bls.G1Element(); - let converted_g1_element = clvm_tools_rs.Program.to(g1element); - console.log(converted_g1_element.toString()); -}); From aa0a7c17f4a5c360ef1417299822c995f93ad9ec Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 03:36:59 -0700 Subject: [PATCH 113/196] Most of the SExp.ts api --- wasm/Cargo.lock | 1 + wasm/Cargo.toml | 1 + wasm/src/jsval.rs | 9 +- wasm/src/objects.rs | 413 ++++++++++++++++++ .../clvm-tools-interface/src/demo/index.ts | 8 - 5 files changed, 423 insertions(+), 9 deletions(-) create mode 100644 wasm/src/objects.rs delete mode 100644 wasm/tests/clvm-tools-interface/src/demo/index.ts diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 7fa9d0781..23466a11e 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -154,6 +154,7 @@ dependencies = [ "clvmr", "js-sys", "num-bigint", + "num-traits", "wasm-bindgen", "wasm-bindgen-test", ] diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index a293f9ac6..1eea79e62 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -23,3 +23,4 @@ wasm-bindgen = "=0.2.83" wasm-bindgen-test = "=0.3.25" js-sys = "0.3.60" num-bigint = "0.4.0" +num-traits = "0.2.15" \ No newline at end of file diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 1d146a672..61f36b0bc 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -18,6 +18,8 @@ use clvm_tools_rs::util::Number; use wasm_bindgen::prelude::*; +use crate::objects::{find_cached_sexp, js_cache_value_from_js}; + const G1_ELEMENT_LENGTH: u32 = 48; pub fn array_to_value(v: Array) -> JsValue { @@ -185,7 +187,12 @@ pub fn detect_g1(loc: &Srcloc, v: &JsValue) -> Option> { } pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { - if v.is_bigint() { + // Already converted value. + if let Ok(res) = js_cache_value_from_js(v) { + find_cached_sexp(res.entry, &res.content).map(|result| { + result.modern.clone() + }).ok() + } else if v.is_bigint() { BigInt::new(v) .ok() .and_then(|v| v.to_string(10).ok()) diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs new file mode 100644 index 000000000..07bfe6f5a --- /dev/null +++ b/wasm/src/objects.rs @@ -0,0 +1,413 @@ +use js_sys; +use js_sys::{Array, JsString, Reflect}; +use num_traits::cast::ToPrimitive; +use std::borrow::Borrow; +use std::cell::{RefCell, RefMut}; +use std::collections::HashMap; +use std::rc::Rc; +use wasm_bindgen::prelude::*; + +use clvmr::Allocator; +use clvm_tools_rs::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType}; +use clvm_tools_rs::classic::clvm::serialize::{SimpleCreateCLVMObject, sexp_to_stream, sexp_from_stream}; +use clvm_tools_rs::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, sha256tree, truthy}; +use clvm_tools_rs::compiler::sexp::SExp; +use clvm_tools_rs::compiler::srcloc::Srcloc; + +use crate::api::{create_clvm_runner_err, get_next_id}; +use crate::jsval::sexp_from_js_object; + +const DEFAULT_CACHE_ENTRIES: usize = 1024; + +struct FunctionWrapperDesc { + export_name: &'static str, + member_name: &'static str, +} + +#[derive(Clone)] +pub struct ObjectCacheMember { + pub modern: Rc, +} + +struct ObjectCache { + cache_data: HashMap, + cache_order: Vec, + cache_length: usize, +} + +pub struct JsCacheValue { + pub entry: i32, + pub content: String +} + +pub fn js_cache_value_from_js(jsval: &JsValue) -> Result { + let entry = js_sys::Reflect::get( + jsval, + &JsString::from("id") + )?.as_f64().ok_or(JsString::from("id was not a number"))?; + let content = js_sys::Reflect::get( + jsval, + &JsString::from("content") + )?.as_string().ok_or(JsString::from("content was not a string"))?; + + Ok(JsCacheValue { entry: entry as i32, content }) +} + +impl Default for ObjectCache { + fn default() -> Self { + ObjectCache { + cache_data: HashMap::default(), + cache_order: Vec::default(), + cache_length: DEFAULT_CACHE_ENTRIES, + } + } +} + +impl ObjectCache { + fn create_or_update_cache_entry(&mut self, id: i32, cache_member: ObjectCacheMember) { + if id < 0 { + // Special nil handling. + return; + } + + if self.cache_order.len() > self.cache_length { + self.cache_data.remove(&self.cache_order[0]); + self.cache_order.remove(0); + } + + self.cache_data.insert(id, cache_member); + self.cache_order.push(id); + } + + fn create_entry_from_sexp(&mut self, id: i32, sexp: Rc) -> Result { + let mut allocator = Allocator::new(); + let node = convert_to_clvm_rs( + &mut allocator, + sexp.clone() + ).map_err(|_| js_sys::JsString::from("could not convert to clvm"))?; + let mut stream = Stream::new(None); + sexp_to_stream(&mut allocator, node, &mut stream); + + self.create_or_update_cache_entry(id, ObjectCacheMember { + modern: sexp.clone(), + }); + + Ok(stream.get_value().hex()) + } + + fn find_or_create_entry_from_hex(&mut self, entry: i32, content: &str) -> Result { + if let Some(res) = self.cache_data.get(&entry) { + return Ok(res.clone()); + } + + let mut allocator = Allocator::new(); + let bytes_from_hex = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(content.to_string()))).map_err(|_| JsString::from("could not parse hex"))?; + let mut stream = Stream::new(Some(bytes_from_hex)); + let parsed = sexp_from_stream( + &mut allocator, + &mut stream, + Box::new(SimpleCreateCLVMObject {}) + ) + .map(|x| x.1) + .map_err(|_| JsString::from("could not parse sexp from hex"))?; + let srcloc = Srcloc::start("*var*"); + let modern = convert_from_clvm_rs( + &mut allocator, + srcloc, + parsed + ).map_err(|_| JsString::from("could not realize parsed sexp"))?; + + let cache_entry = ObjectCacheMember { + modern + }; + self.create_or_update_cache_entry(entry, cache_entry.clone()); + + Ok(cache_entry) + } +} + +static WRAPPED_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ + FunctionWrapperDesc { + export_name: "toString", + member_name: "to_string_internal", + }, + FunctionWrapperDesc { + export_name: "as_pair", + member_name: "as_pair_internal", + }, + FunctionWrapperDesc { + export_name: "listp", + member_name: "listp_internal", + }, + FunctionWrapperDesc { + export_name: "nullp", + member_name: "nullp_internal", + }, + FunctionWrapperDesc { + export_name: "as_int", + member_name: "as_int_internal", + }, + FunctionWrapperDesc { + export_name: "as_bigint", + member_name: "as_bigint_internal", + }, + FunctionWrapperDesc { + export_name: "first", + member_name: "first_internal", + }, + FunctionWrapperDesc { + export_name: "rest", + member_name: "rest_internal", + }, + FunctionWrapperDesc { + export_name: "cons", + member_name: "cons_internal", + } +]; + +thread_local! { + static OBJECT_CACHE: RefCell = { + return RefCell::new(ObjectCache::default()); + }; + static PROGRAM_PROTOTYPE: RefCell> = RefCell::new(None); + static SRCLOC: Srcloc = Srcloc::start("*var*"); +} + +fn create_cached_sexp(id: i32, sexp: Rc) -> Result { + if !truthy(sexp.clone()) { + return Ok("80".to_string()); + } + OBJECT_CACHE.with(|ocache| { + let mut mut_object_cache_ref: RefMut = ocache.borrow_mut(); + mut_object_cache_ref.create_entry_from_sexp(id, sexp) + }) +} + +fn get_srcloc() -> Srcloc { + SRCLOC.with(|s| s.clone()) +} + +pub fn find_cached_sexp(entry: i32, content: &str) -> Result { + if content == "80" { + return Ok(ObjectCacheMember { + modern: Rc::new(SExp::Nil(get_srcloc())) + }); + } + + OBJECT_CACHE.with(|ocache| { + let mut mut_object_cache_ref: RefMut = ocache.borrow_mut(); + mut_object_cache_ref.find_or_create_entry_from_hex(entry, content) + }) +} + +// Strategy for Program objects. +// We'll provide a Program object that allows users to have something that +// acts js-y but conserves compute time when possible. +// +// The result object we'll give back contain a string representation of the +// program they're associated with but also a cache hint. If the cache object +// doesn't exist we'll re-parse the hex and re-cache it. +// +// The object is structured like this: +// +// {"cache-hint":33, "hex":"ff..."} +// +// Cache hints are never reused, and cleared when the counter transitions from +// low half to high half or vice versa. +// +// The object's prototype will include methods for Program, such as cons and call +// the real static methods of Program. +#[wasm_bindgen(inspectable)] +pub struct Program { } + +// Build prototype +fn get_program_prototype() -> Result { + // We've already built the program prototype object. + if let Some(pp) = PROGRAM_PROTOTYPE.with(|pp| pp.borrow().clone()) { + return Ok(pp); + } + + let prototype = js_sys::Object::new(); + + // toString function. + let program_self = js_sys::eval("Program")?; + for func_wrapper_desc in WRAPPED_FUNCTIONS.iter() { + let to_string_fun = js_sys::Function::new_with_args( + "", + &format!("const t = this; return function() {{ let args = Array.prototype.slice.call(arguments); args.unshift(this); return t.{}.apply(null, args); }}", func_wrapper_desc.member_name) + ); + + let to_string_final = to_string_fun.call0(&program_self)?; + js_sys::Reflect::set( + &prototype, + &js_sys::JsString::from(func_wrapper_desc.export_name), + &to_string_final, + )?; + } + + PROGRAM_PROTOTYPE.with(|pp| { + pp.replace(Some(prototype.clone().into())); + }); + + Ok(prototype.into()) +} + +pub fn finish_new_object(id: i32, encoded_hex: &str) -> Result { + let prototype = get_program_prototype()?; + + let new_object = js_sys::Object::new(); + js_sys::Reflect::set_prototype_of( + &new_object, + &prototype + )?; + + js_sys::Reflect::set( + &new_object, + &js_sys::JsString::from("content"), + &js_sys::JsString::from(encoded_hex), + )?; + js_sys::Reflect::set( + &new_object, + &js_sys::JsString::from("id"), + &js_sys::Number::from(id), + )?; + + Ok(new_object.into()) +} + +#[wasm_bindgen] +impl Program { + #[wasm_bindgen] + pub fn to(input: &JsValue) -> Result { + let loc = get_srcloc(); + let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| Err(create_clvm_runner_err(format!("unable to convert to value"))))?; + + let new_id = get_next_id(); + + let encoded = create_cached_sexp(new_id, sexp)?; + + // Build the object + finish_new_object(new_id, &encoded) + } + + #[wasm_bindgen] + pub fn null() -> Result { + let new_id = get_next_id(); + let encoded = create_cached_sexp(new_id, Rc::new(SExp::Nil(get_srcloc())))?; + + finish_new_object(new_id, &encoded) + } + + #[wasm_bindgen] + pub fn sha256tree_internal(obj: &JsValue) -> Result, JsValue> { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + Ok(sha256tree(cached.modern.clone())) + } + + #[wasm_bindgen] + pub fn to_string_internal(obj: &JsValue) -> Result { + js_sys::Reflect::get( + obj, + &js_sys::JsString::from("content"), + ) + } + + #[wasm_bindgen] + pub fn as_pair_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + if let SExp::Cons(_, a, b) = cached.modern.borrow() { + let id_a = get_next_id(); + let new_cached_a = create_cached_sexp(id_a, a.clone())?; + let object_a = finish_new_object(id_a, &new_cached_a)?; + let id_b = get_next_id(); + let new_cached_b = create_cached_sexp(id_b, b.clone())?; + let object_b = finish_new_object(id_b, &new_cached_b)?; + + let result_value = Array::new(); + Reflect::set( + &result_value, + &JsString::from("0"), + &object_a, + )?; + Reflect::set( + &result_value, + &JsString::from("1"), + &object_b, + )?; + return Ok(result_value.into()); + } + + Ok(JsValue::null()) + } + + #[wasm_bindgen] + pub fn listp_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + Ok(cacheval.content.starts_with("ff")) + } + + #[wasm_bindgen] + pub fn nullp_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + Ok(cacheval.content == "80") + } + + #[wasm_bindgen] + pub fn as_int_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + let number = cached.modern.get_number().map_err(|_| JsString::from("not a number"))?; + (number.to_i32()).ok_or(JsString::from("number out of range").into()) + } + + #[wasm_bindgen] + pub fn as_bigint_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + let number = cached.modern.get_number().map_err(|_| JsString::from("not a number"))?; + let num_string = number.to_string(); + let num_str: &str = &num_string; + js_sys::BigInt::new(&JsString::from(num_str)).map_err(|_| JsString::from("couldn't construct bigint").into()) + } + + #[wasm_bindgen] + pub fn first_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + if let SExp::Cons(_, a, _) = cached.modern.borrow() { + let id_a = get_next_id(); + let new_cached_a = create_cached_sexp(id_a, a.clone())?; + return finish_new_object(id_a, &new_cached_a); + } + + Err(JsString::from("not a cons").into()) + } + + #[wasm_bindgen] + pub fn rest_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + if let SExp::Cons(_, _, a) = cached.modern.borrow() { + let id_a = get_next_id(); + let new_cached_a = create_cached_sexp(id_a, a.clone())?; + return finish_new_object(id_a, &new_cached_a); + } + + Err(JsString::from("not a cons").into()) + } + + pub fn cons_internal(obj: &JsValue, other: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + + let other_val = js_cache_value_from_js(other)?; + let other_cache = find_cached_sexp(other_val.entry, &other_val.content)?; + + let new_id = get_next_id(); + let new_sexp = Rc::new(SExp::Cons(get_srcloc(), cached.modern.clone(), other_cache.modern.clone())); + let new_cached = create_cached_sexp(new_id, new_sexp)?; + finish_new_object(new_id, &new_cached) + } +} diff --git a/wasm/tests/clvm-tools-interface/src/demo/index.ts b/wasm/tests/clvm-tools-interface/src/demo/index.ts deleted file mode 100644 index 69b6174f7..000000000 --- a/wasm/tests/clvm-tools-interface/src/demo/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import MyLibrary from "../lib"; -const myLibraryInstance = new MyLibrary(); - -document.querySelector("body").innerHTML = `

Hello World!

`; - -console.log("myLibraryInstance", myLibraryInstance); - -myLibraryInstance.myMethod(); \ No newline at end of file From e343cfc245ed03068b81338cf0d15ada65684fd9 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 03:38:40 -0700 Subject: [PATCH 114/196] tests --- .../src/lib/tests/index.test.ts | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts new file mode 100644 index 000000000..a3bd2e7d7 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -0,0 +1,103 @@ +import * as assert from 'assert'; +import * as bls_loader from 'bls-signatures'; +const {h, Program} = require('../../../../../pkg/clvm_tools_wasm'); + +it('Has BLS signatures support', async () => { + let bls = await bls_loader.default(); + let g1element = new bls.G1Element(); + let converted_g1_element = Program.to(g1element); + assert.equal('b0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', converted_g1_element.toString()); +}); + +it('Has the "h" function', async () => { + let unhexed = h('21203031'); + assert.equal([0x21, 0x20, 0x30, 0x31].toString(), unhexed.toString()); +}); + +it('Converts to string', async () => { + let converted_sexp = Program.to([1, 2, 3]); + assert.equal("ff01ff02ff0380", converted_sexp.toString()); +}); + +it('Accepts already converted objects', async () => { + let converted_sexp = Program.to([1, 2, 3]); + let twice_converted = Program.to(converted_sexp); + assert.equal("ff01ff02ff0380", twice_converted.toString()); +}); + +it('Has as_pair', async () => { + let converted_sexp = Program.to([1, 2, 3]); + let as_pair = converted_sexp.as_pair(); + assert.equal("01", as_pair[0].toString()); + assert.equal("ff02ff0380", as_pair[1].toString()); +}); + +it('Has null', async () => { + assert.equal(Program.null().toString(), '80'); +}); + +it('Has listp', async () => { + let is_list = Program.to([1,2,3]); + let isnt_list = Program.to(456); + assert.equal(is_list.listp(), true); + assert.equal(isnt_list.listp(), false); +}); + +it('Has nullp', async () => { + let is_null = Program.to([]); + let is_also_null = Program.to(0); + let isnt_null = Program.to(7); + let isnt_also_null = Program.to([99,101]); + assert.equal(is_null.nullp(), true); + assert.equal(is_also_null.nullp(), true); + assert.equal(isnt_null.nullp(), false); + assert.equal(isnt_also_null.nullp(), false); +}); + +it('Has as_int', async () => { + let int_value = Program.to(7).as_int(); + assert.equal(int_value, 7); + try { + non_int_value = Program.to([7,13]).as_int(); + assert.that(false); + } catch (e) { + assert.equal(e.toString(), "not a number"); + } +}); + +it('Has as_bigint', async () => { + let int_value = Program.to(10000000000000000000000n).as_bigint(); + assert.equal(int_value, 10000000000000000000000n); + try { + non_int_value = Program.to([7,13]).as_bigint(); + assert.that(false); + } catch (e) { + assert.equal(e.toString(), "not a number"); + } +}); + +it('Has first and rest', async () => { + let test_list = Program.to([7,13,17,23]); + assert.equal(test_list.first().toString(), '07'); + assert.equal(test_list.rest().toString(), 'ff0dff11ff1780'); + try { + Program.to([]).first(); + assert.that(false); + } catch (e) { + assert.equal(e.toString(), "not a cons"); + } + try { + Program.to([]).rest(); + assert.that(false); + } catch (e) { + assert.equal(e.toString(), "not a cons"); + } +}); + +it('Has cons', async () => { + let test_1 = Program.to(7); + let test_2 = Program.to([8,9,10]); + let consed = test_1.cons(test_2); + let test_3 = Program.to([7,8,9,10]); + assert.equal(consed.toString(), test_3.toString()); +}); From 2b044b6e8483874842743c52254c6dc478dcf8a6 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 04:06:58 -0700 Subject: [PATCH 115/196] Add run and from_hex --- wasm/src/objects.rs | 64 ++++++++++++++++++- .../src/lib/tests/index.test.ts | 6 ++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 07bfe6f5a..16704e9a3 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -10,6 +10,7 @@ use wasm_bindgen::prelude::*; use clvmr::Allocator; use clvm_tools_rs::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType}; use clvm_tools_rs::classic::clvm::serialize::{SimpleCreateCLVMObject, sexp_to_stream, sexp_from_stream}; +use clvm_tools_rs::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; use clvm_tools_rs::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, sha256tree, truthy}; use clvm_tools_rs::compiler::sexp::SExp; use clvm_tools_rs::compiler::srcloc::Srcloc; @@ -162,7 +163,11 @@ static WRAPPED_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ FunctionWrapperDesc { export_name: "cons", member_name: "cons_internal", - } + }, + FunctionWrapperDesc { + export_name: "run", + member_name: "run_internal", + }, ]; thread_local! { @@ -290,6 +295,13 @@ impl Program { finish_new_object(new_id, &encoded) } + #[wasm_bindgen] + pub fn from_hex(input: &str) -> Result { + let new_id = get_next_id(); + let obj = finish_new_object(new_id, input)?; + Program::to(&obj) + } + #[wasm_bindgen] pub fn null() -> Result { let new_id = get_next_id(); @@ -398,6 +410,7 @@ impl Program { Err(JsString::from("not a cons").into()) } + #[wasm_bindgen] pub fn cons_internal(obj: &JsValue, other: &JsValue) -> Result { let cacheval = js_cache_value_from_js(obj)?; let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; @@ -410,4 +423,53 @@ impl Program { let new_cached = create_cached_sexp(new_id, new_sexp)?; finish_new_object(new_id, &new_cached) } + + #[wasm_bindgen] + pub fn run_internal(obj: &JsValue, args: &JsValue) -> Result { + let progval = js_cache_value_from_js(obj)?; + let prog_cache = find_cached_sexp(progval.entry, &progval.content)?; + + let argval = js_cache_value_from_js(args)?; + let arg_cache = find_cached_sexp(argval.entry, &argval.content)?; + + let mut allocator = Allocator::new(); + let prog_classic = convert_to_clvm_rs( + &mut allocator, + prog_cache.modern.clone() + ).map_err(|_| { + let err: JsValue = JsString::from("error converting program").into(); + err + })?; + let arg_classic = convert_to_clvm_rs( + &mut allocator, + arg_cache.modern.clone() + ).map_err(|_| { + let err: JsValue = JsString::from("error converting args").into(); + err + })?; + + let runner = DefaultProgramRunner::default(); + let run_result = + runner.run_program( + &mut allocator, + prog_classic, + arg_classic, + None + ).map_err(|e| { + let err_str: &str = &e.1; + let err: JsValue = JsString::from(err_str).into(); + err + })?; + let modern_result = convert_from_clvm_rs( + &mut allocator, + get_srcloc(), + run_result.1 + ).map_err(|_| { + let err: JsValue = JsString::from("error converting result").into(); + err + })?; + let result_id = get_next_id(); + let new_cached_result = create_cached_sexp(result_id, modern_result)?; + finish_new_object(result_id, &new_cached_result) + } } diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index a3bd2e7d7..31eaf0f1e 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -101,3 +101,9 @@ it('Has cons', async () => { let test_3 = Program.to([7,8,9,10]); assert.equal(consed.toString(), test_3.toString()); }); + +it('Has run', async () => { + let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); + let args = Program.to([13]); + assert.equal(program.run(args).toString(), '8200a8'); +}); From 7aff57a2c415d314572f0b999eccf5c072a3cf95 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 04:12:26 -0700 Subject: [PATCH 116/196] generalize support for objects with a serialize method --- wasm/src/jsval.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 61f36b0bc..2c6d936ec 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -20,8 +20,6 @@ use wasm_bindgen::prelude::*; use crate::objects::{find_cached_sexp, js_cache_value_from_js}; -const G1_ELEMENT_LENGTH: u32 = 48; - pub fn array_to_value(v: Array) -> JsValue { let jref: &JsValue = v.as_ref(); jref.clone() @@ -160,15 +158,12 @@ fn location(o: &Object) -> Option { }) } -pub fn detect_g1(loc: &Srcloc, v: &JsValue) -> Option> { +pub fn detect_serializable(loc: &Srcloc, v: &JsValue) -> Option> { let serialize_key = JsValue::from_str("serialize"); js_sys::Reflect::get(v, &serialize_key).ok().and_then(|serialize| { Reflect::apply(serialize.unchecked_ref(), v, &js_sys::Array::new()).ok().and_then(|array| { Array::try_from(array).ok().and_then(|array| { let mut bytes_array: Vec = vec![]; - if array.length() != G1_ELEMENT_LENGTH { - return None; - } for item in array.iter() { if let Some(n) = item.as_f64() { if n < 0.0 || n > 255.0 { @@ -202,7 +197,7 @@ pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { } else if let Some(fval) = v.as_f64() { (fval as i64).to_bigint() .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) - } else if let Some(g1_bytes) = detect_g1(&sstart, v) { + } else if let Some(g1_bytes) = detect_serializable(&sstart, v) { Some(g1_bytes) } else if Array::is_array(v) { let a = Array::from(v); From 20986a68cec02a1e159b85c7fdcac7056965c391 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 04:22:09 -0700 Subject: [PATCH 117/196] Add 't' tuple function --- wasm/src/api.rs | 6 ++++++ .../clvm-tools-interface/src/lib/tests/index.test.ts | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/wasm/src/api.rs b/wasm/src/api.rs index 499085d0c..b990b3bdc 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -34,6 +34,7 @@ use crate::jsval::{ btreemap_to_object, get_property, js_object_from_sexp, js_pair, object_to_value, read_string_to_string_map, sexp_from_js_object, }; +use crate::objects::Program; #[cfg(feature = "wee_alloc")] #[global_allocator] @@ -499,3 +500,8 @@ pub fn h(v: String) -> Result, JsValue> { let hex_data = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(v))).map_err(|_| js_sys::JsString::from("bad hex input"))?; Ok(hex_data.data().clone()) } + +#[wasm_bindgen] +pub fn t(a: &JsValue, b: &JsValue) -> Result { + Program::cons_internal(a, b) +} diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 31eaf0f1e..39ccbf6ac 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import * as bls_loader from 'bls-signatures'; -const {h, Program} = require('../../../../../pkg/clvm_tools_wasm'); +const {h, t, Program} = require('../../../../../pkg/clvm_tools_wasm'); it('Has BLS signatures support', async () => { let bls = await bls_loader.default(); @@ -102,6 +102,14 @@ it('Has cons', async () => { assert.equal(consed.toString(), test_3.toString()); }); +it('Has the t function', async () => { + let p1 = Program.to(7); + let p2 = Program.to(9); + let tuple = t(p1, p2); + let consed = p1.cons(p2); + assert.equal(tuple.toString(), consed.toString()); +}); + it('Has run', async () => { let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); let args = Program.to([13]); From ceb819fd7a9750285f9e89e9a77d65f5cfa058e0 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 08:34:13 -0700 Subject: [PATCH 118/196] Give tuple a prototype and a conversion function that can be recognized by the internal converter --- wasm/src/api.rs | 2 +- wasm/src/jsval.rs | 13 ++++ wasm/src/objects.rs | 61 ++++++++++++++++++- .../src/lib/tests/index.test.ts | 2 +- 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/wasm/src/api.rs b/wasm/src/api.rs index b990b3bdc..bb5f3aab6 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -503,5 +503,5 @@ pub fn h(v: String) -> Result, JsValue> { #[wasm_bindgen] pub fn t(a: &JsValue, b: &JsValue) -> Result { - Program::cons_internal(a, b) + Program::as_pair_internal(&Program::cons_internal(a, b)?) } diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 2c6d936ec..611017972 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -181,6 +181,17 @@ pub fn detect_serializable(loc: &Srcloc, v: &JsValue) -> Option> { }) } +pub fn detect_convertible(v: &JsValue) -> Result, JsValue> { + let convert_key = JsValue::from_str("to_program"); + let to_program = js_sys::Reflect::get(v, &convert_key)?; + let call_args = js_sys::Array::new(); + call_args.push(v); + let call_result = Reflect::apply(to_program.unchecked_ref(), v, &call_args)?; + let cacheval = js_cache_value_from_js(&call_result)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + Ok(cached.modern.clone()) +} + pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { // Already converted value. if let Ok(res) = js_cache_value_from_js(v) { @@ -199,6 +210,8 @@ pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) } else if let Some(g1_bytes) = detect_serializable(&sstart, v) { Some(g1_bytes) + } else if let Some(converted) = detect_convertible(v).ok() { + Some(converted) } else if Array::is_array(v) { let a = Array::from(v); let mut result_value = Rc::new(SExp::Nil(Srcloc::start(&"*js*".to_string()))); diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 16704e9a3..4bbf68e53 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -127,7 +127,7 @@ impl ObjectCache { } } -static WRAPPED_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ +static PROGRAM_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ FunctionWrapperDesc { export_name: "toString", member_name: "to_string_internal", @@ -170,11 +170,19 @@ static WRAPPED_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ }, ]; +static TUPLE_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ + FunctionWrapperDesc { + export_name: "to_program", + member_name: "tuple_to_program_internal", + }, +]; + thread_local! { static OBJECT_CACHE: RefCell = { return RefCell::new(ObjectCache::default()); }; static PROGRAM_PROTOTYPE: RefCell> = RefCell::new(None); + static TUPLE_PROTOTYPE: RefCell> = RefCell::new(None); static SRCLOC: Srcloc = Srcloc::start("*var*"); } @@ -234,9 +242,8 @@ fn get_program_prototype() -> Result { let prototype = js_sys::Object::new(); - // toString function. let program_self = js_sys::eval("Program")?; - for func_wrapper_desc in WRAPPED_FUNCTIONS.iter() { + for func_wrapper_desc in PROGRAM_FUNCTIONS.iter() { let to_string_fun = js_sys::Function::new_with_args( "", &format!("const t = this; return function() {{ let args = Array.prototype.slice.call(arguments); args.unshift(this); return t.{}.apply(null, args); }}", func_wrapper_desc.member_name) @@ -257,6 +264,35 @@ fn get_program_prototype() -> Result { Ok(prototype.into()) } +fn get_tuple_prototype() -> Result { + if let Some(pp) = TUPLE_PROTOTYPE.with(|pp| pp.borrow().clone()) { + return Ok(pp); + } + + let prototype = js_sys::Object::new(); + + let program_self = js_sys::eval("Program")?; + for func_wrapper_desc in TUPLE_FUNCTIONS.iter() { + let to_string_fun = js_sys::Function::new_with_args( + "", + &format!("const t = this; return function() {{ let args = Array.prototype.slice.call(arguments); args.unshift(this); return t.{}.apply(null, args); }}", func_wrapper_desc.member_name) + ); + + let to_string_final = to_string_fun.call0(&program_self)?; + js_sys::Reflect::set( + &prototype, + &js_sys::JsString::from(func_wrapper_desc.export_name), + &to_string_final, + )?; + } + + TUPLE_PROTOTYPE.with(|pp| { + pp.replace(Some(prototype.clone().into())); + }); + + Ok(prototype.into()) +} + pub fn finish_new_object(id: i32, encoded_hex: &str) -> Result { let prototype = get_program_prototype()?; @@ -327,8 +363,10 @@ impl Program { #[wasm_bindgen] pub fn as_pair_internal(obj: &JsValue) -> Result { + let prototype = get_tuple_prototype()?; let cacheval = js_cache_value_from_js(obj)?; let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + if let SExp::Cons(_, a, b) = cached.modern.borrow() { let id_a = get_next_id(); let new_cached_a = create_cached_sexp(id_a, a.clone())?; @@ -348,6 +386,10 @@ impl Program { &JsString::from("1"), &object_b, )?; + Reflect::set_prototype_of( + &result_value, + &prototype + )?; return Ok(result_value.into()); } @@ -472,4 +514,17 @@ impl Program { let new_cached_result = create_cached_sexp(result_id, modern_result)?; finish_new_object(result_id, &new_cached_result) } + + #[wasm_bindgen] + pub fn tuple_to_program_internal(obj: &JsValue) -> Result { + let a = js_sys::Reflect::get( + obj, + &JsString::from("0"), + )?; + let b = js_sys::Reflect::get( + obj, + &JsString::from("1"), + )?; + Program::cons_internal(&a, &b) + } } diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 39ccbf6ac..7eb7a3b9f 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -107,7 +107,7 @@ it('Has the t function', async () => { let p2 = Program.to(9); let tuple = t(p1, p2); let consed = p1.cons(p2); - assert.equal(tuple.toString(), consed.toString()); + assert.equal(Program.to(tuple).toString(), consed.toString()); }); it('Has run', async () => { From 7cbc9bd4b51819e8e5937fddb905301099553283 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 08:50:10 -0700 Subject: [PATCH 119/196] Add as_bin --- wasm/src/objects.rs | 14 ++++++++++++++ .../src/lib/tests/index.test.ts | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 4bbf68e53..78bf30226 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -152,6 +152,10 @@ static PROGRAM_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ export_name: "as_bigint", member_name: "as_bigint_internal", }, + FunctionWrapperDesc { + export_name: "as_bin", + member_name: "as_bin_internal", + }, FunctionWrapperDesc { export_name: "first", member_name: "first_internal", @@ -527,4 +531,14 @@ impl Program { )?; Program::cons_internal(&a, &b) } + + #[wasm_bindgen] + pub fn as_bin_internal(obj: &JsValue) -> Result, JsValue> { + let convert = Reflect::get( + obj, + &JsString::from("content"), + )?.as_string().ok_or(JsString::from("content wasn't a hex string"))?; + let bytes = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(convert))).map_err(|_| JsString::from("could not convert to binary data"))?; + Ok(bytes.data().clone()) + } } diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 7eb7a3b9f..29a976955 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -110,6 +110,12 @@ it('Has the t function', async () => { assert.equal(Program.to(tuple).toString(), consed.toString()); }); +it('Has as_bin', async() => { + let test_data = Program.to([7,8,9,10]); + let as_bin = test_data.as_bin(); + assert.equal([255,7,255,8,255,9,255,10,128].toString(), as_bin.toString()); +}); + it('Has run', async () => { let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); let args = Program.to([13]); From 757432478055d7d588c5b6b64b8bddaacdf349e6 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 08:58:41 -0700 Subject: [PATCH 120/196] Add list_len --- wasm/src/objects.rs | 21 +++++++++++++++++++ .../src/lib/tests/index.test.ts | 11 +++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 78bf30226..a4764a680 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -172,6 +172,10 @@ static PROGRAM_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ export_name: "run", member_name: "run_internal", }, + FunctionWrapperDesc { + export_name: "list_len", + member_name: "list_len_internal", + }, ]; static TUPLE_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ @@ -541,4 +545,21 @@ impl Program { let bytes = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(convert))).map_err(|_| JsString::from("could not convert to binary data"))?; Ok(bytes.data().clone()) } + + #[wasm_bindgen] + pub fn list_len_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + let mut val_ref = cached.modern.clone(); + let mut count: i32 = 0; + loop { + if let SExp::Cons(_, _, b) = val_ref.borrow() { + val_ref = b.clone(); + count += 1; + } else { + break; + } + } + Ok(count) + } } diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 29a976955..edef35784 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -110,12 +110,21 @@ it('Has the t function', async () => { assert.equal(Program.to(tuple).toString(), consed.toString()); }); -it('Has as_bin', async() => { +it('Has as_bin', async () => { let test_data = Program.to([7,8,9,10]); let as_bin = test_data.as_bin(); assert.equal([255,7,255,8,255,9,255,10,128].toString(), as_bin.toString()); }); +it('Has list_len', async () => { + let list_data = Program.to([7,8,9,10]); + let list_len = list_data.list_len(); + assert.equal(list_len, 4); + let not_list = Program.to(16); + let not_list_len = not_list.list_len(); + assert.equal(not_list_len, 0); +}); + it('Has run', async () => { let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); let args = Program.to([13]); From fe7f125361868550d56f8241c667bad106b94870 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 10:29:17 -0700 Subject: [PATCH 121/196] Add equal_to --- wasm/src/objects.rs | 17 +++++++++++++++++ .../src/lib/tests/index.test.ts | 17 +++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index a4764a680..505de1a18 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -176,6 +176,10 @@ static PROGRAM_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ export_name: "list_len", member_name: "list_len_internal", }, + FunctionWrapperDesc { + export_name: "equal_to", + member_name: "equal_to_internal", + } ]; static TUPLE_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ @@ -562,4 +566,17 @@ impl Program { } Ok(count) } + + #[wasm_bindgen] + pub fn equal_to_internal(a: &JsValue, b: &JsValue) -> Result { + let a_cacheval = js_cache_value_from_js(a)?; + let a_cached = find_cached_sexp(a_cacheval.entry, &a_cacheval.content)?; + let b_cacheval = js_cache_value_from_js(b)?; + let b_cached = find_cached_sexp(b_cacheval.entry, &b_cacheval.content)?; + // Short circuit address equality. + if Rc::as_ptr(&a_cached.modern) == Rc::as_ptr(&b_cached.modern) { + return Ok(true); + } + Ok(a_cached.modern == b_cached.modern) + } } diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index edef35784..9061a2594 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -59,7 +59,7 @@ it('Has as_int', async () => { assert.equal(int_value, 7); try { non_int_value = Program.to([7,13]).as_int(); - assert.that(false); + assert.fail(); } catch (e) { assert.equal(e.toString(), "not a number"); } @@ -70,7 +70,7 @@ it('Has as_bigint', async () => { assert.equal(int_value, 10000000000000000000000n); try { non_int_value = Program.to([7,13]).as_bigint(); - assert.that(false); + assert.fail(); } catch (e) { assert.equal(e.toString(), "not a number"); } @@ -82,13 +82,13 @@ it('Has first and rest', async () => { assert.equal(test_list.rest().toString(), 'ff0dff11ff1780'); try { Program.to([]).first(); - assert.that(false); + assert.fail(); } catch (e) { assert.equal(e.toString(), "not a cons"); } try { Program.to([]).rest(); - assert.that(false); + assert.fail(); } catch (e) { assert.equal(e.toString(), "not a cons"); } @@ -125,6 +125,15 @@ it('Has list_len', async () => { assert.equal(not_list_len, 0); }); +it('Has equal_to', async () => { + let p1 = Program.to([7,8,[9,10],11]); + let p2 = Program.from_hex('ff07ff08ffff09ff0a80ff0b80'); + let p3 = Program.to([7,8,[9,11],11]); + assert.ok(p1.equal_to(p2)); + assert.ok(!p1.equal_to(p3)); + assert.ok(!p2.equal_to(p3)); +}); + it('Has run', async () => { let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); let args = Program.to([13]); From a3a2a166016c1c4dd32fd984df75b0e98a508f2c Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 11:26:16 -0700 Subject: [PATCH 122/196] Add as_javascript, sort out improper list structure --- wasm/src/api.rs | 8 +- wasm/src/jsval.rs | 77 ++++--------------- wasm/src/objects.rs | 25 ++++-- .../src/lib/tests/index.test.ts | 9 +++ 4 files changed, 44 insertions(+), 75 deletions(-) diff --git a/wasm/src/api.rs b/wasm/src/api.rs index bb5f3aab6..fe319cad5 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -147,7 +147,7 @@ impl CldbSingleBespokeOverride for JsBespokeOverride { // When the user returns, try to convert the result back to sexp. fn get_override(&self, env: Rc) -> Result, RunFailure> { let args = js_sys::Array::new(); - args.set(0, js_object_from_sexp(env.clone())); + args.set(0, js_object_from_sexp(env.clone()).map_err(|_| RunFailure::RunErr(env.loc(), "error converting override value".to_string()))?); self.fun .apply(&JsValue::null(), &args) .map_err(|e| { @@ -253,7 +253,7 @@ pub fn create_clvm_runner( #[wasm_bindgen] pub fn final_value(runner: i32) -> JsValue { with_runner(runner, |r| { - r.cldbrun.final_result().map(|v| js_object_from_sexp(v)) + r.cldbrun.final_result().map(|v| js_object_from_sexp(v).unwrap_or_else(|e| e)) }) .unwrap_or_else(|| JsValue::null()) } @@ -475,7 +475,7 @@ pub fn repl_run_string(repl_id: i32, input: String) -> JsValue { )) } }) - .map(|v| v.map(|v| js_object_from_sexp(v.to_sexp()))) + .map(|v| v.map(|v| js_object_from_sexp(v.to_sexp()).unwrap_or_else(|e| e))) .unwrap_or_else(|e| { Some(create_clvm_runner_err(format!( "{}: {}", @@ -503,5 +503,5 @@ pub fn h(v: String) -> Result, JsValue> { #[wasm_bindgen] pub fn t(a: &JsValue, b: &JsValue) -> Result { - Program::as_pair_internal(&Program::cons_internal(a, b)?) + Program::as_pair_internal(&Program::cons_internal(&Program::to(a)?, &Program::to(b)?)?) } diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 611017972..0b9a65e13 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -18,6 +18,7 @@ use clvm_tools_rs::util::Number; use wasm_bindgen::prelude::*; +use crate::api::t; use crate::objects::{find_cached_sexp, js_cache_value_from_js}; pub fn array_to_value(v: Array) -> JsValue { @@ -37,77 +38,27 @@ pub fn js_pair(a: JsValue, b: JsValue) -> JsValue { array_to_value(pair_array) } -pub fn js_from_location(l: Srcloc) -> JsValue { - let loc_array = Array::new(); - let file_copy: &String = l.file.borrow(); - loc_array.set( - 0, - js_pair(JsValue::from_str("file"), JsValue::from_str(&file_copy)), - ); - loc_array.set( - 1, - js_pair(JsValue::from_str("line"), JsValue::from_f64(l.line as f64)), - ); - loc_array.set( - 2, - js_pair(JsValue::from_str("col"), JsValue::from_f64(l.col as f64)), - ); - match l.until { - Some(u) => { - let til_array = Array::new(); - til_array.set( - 0, - js_pair(JsValue::from_str("line"), JsValue::from_f64(u.line as f64)), - ); - til_array.set( - 1, - js_pair(JsValue::from_str("col"), JsValue::from_f64(u.col as f64)), - ); - loc_array.set( - 3, - object_to_value(Object::from_entries(&til_array).as_ref().unwrap()), - ); - } - _ => {} - } - object_to_value(Object::from_entries(&loc_array).as_ref().unwrap()) -} - -pub fn js_object_from_sexp(v: Rc) -> JsValue { +pub fn js_object_from_sexp(v: Rc) -> Result { match v.borrow() { - SExp::Nil(_) => JsValue::null(), - SExp::Integer(_, i) => JsValue::bigint_from_str(&i.to_string()), + SExp::Nil(_) => Ok(JsValue::null()), + SExp::Integer(_, i) => Ok(JsValue::bigint_from_str(&i.to_string())), SExp::QuotedString(_, _, q) => { - JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode()) + Ok(JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode())) } SExp::Atom(_, q) => { - JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode()) + Ok(JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode())) } - SExp::Cons(l, a, b) => v - .proper_list() - .map(|lst| { + SExp::Cons(_, a, b) => { + if let Some(lst) = v.proper_list() { let array = Array::new(); for i in 0..lst.len() { - array.set(i as u32, js_object_from_sexp(Rc::new(lst[i].clone()))); + array.set(i as u32, js_object_from_sexp(Rc::new(lst[i].clone())).unwrap_or_else(|e| e)); } - array_to_value(array) - }) - .unwrap_or_else(|| { - let array = Array::new(); - array.set( - 0, - js_pair(JsValue::from_str("location"), js_from_location(l.clone())), - ); - let pair: JsValue = js_pair( - JsValue::from_str("pair"), - js_pair( - js_object_from_sexp(a.clone()), - js_object_from_sexp(b.clone()), - ), - ); - array.set(1, pair); - object_to_value(&Object::from_entries(&array).unwrap()) - }), + Ok(array_to_value(array)) + } else { + t(&js_object_from_sexp(a.clone())?, &js_object_from_sexp(b.clone())?) + } + } } } diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 505de1a18..390d1efa6 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -16,7 +16,7 @@ use clvm_tools_rs::compiler::sexp::SExp; use clvm_tools_rs::compiler::srcloc::Srcloc; use crate::api::{create_clvm_runner_err, get_next_id}; -use crate::jsval::sexp_from_js_object; +use crate::jsval::{js_object_from_sexp, sexp_from_js_object}; const DEFAULT_CACHE_ENTRIES: usize = 1024; @@ -179,7 +179,11 @@ static PROGRAM_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ FunctionWrapperDesc { export_name: "equal_to", member_name: "equal_to_internal", - } + }, + FunctionWrapperDesc { + export_name: "as_javascript", + member_name: "as_javascript_internal", + }, ]; static TUPLE_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ @@ -388,15 +392,13 @@ impl Program { let object_b = finish_new_object(id_b, &new_cached_b)?; let result_value = Array::new(); + result_value.set(0, object_a); + result_value.set(1, object_b); + // Support reading as a classic clvm input. Reflect::set( &result_value, - &JsString::from("0"), - &object_a, - )?; - Reflect::set( + &JsString::from("pair"), &result_value, - &JsString::from("1"), - &object_b, )?; Reflect::set_prototype_of( &result_value, @@ -579,4 +581,11 @@ impl Program { } Ok(a_cached.modern == b_cached.modern) } + + #[wasm_bindgen] + pub fn as_javascript_internal(obj: &JsValue) -> Result { + let cacheval = js_cache_value_from_js(obj)?; + let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; + js_object_from_sexp(cached.modern.clone()) + } } diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 9061a2594..bd3672cc1 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -134,6 +134,15 @@ it('Has equal_to', async () => { assert.ok(!p2.equal_to(p3)); }); +it('Has as_javascript', async () => { + let tuple = t(9,10); + let original = [7,8,tuple,11]; + let p1 = Program.to(original); + let p1_as_js = p1.as_javascript(); + console.log(p1_as_js); + assert.equal(original.toString(), p1_as_js.toString()); +}); + it('Has run', async () => { let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); let args = Program.to([13]); From 5876f04f9ee9506cc6231c73d2ca28af97f7e898 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 22 Aug 2023 11:28:35 -0700 Subject: [PATCH 123/196] Ensure that we exercise a compilicated enough improper list --- wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index bd3672cc1..b18f13312 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -135,11 +135,10 @@ it('Has equal_to', async () => { }); it('Has as_javascript', async () => { - let tuple = t(9,10); - let original = [7,8,tuple,11]; + let tuple = t(9,(t(10,11))); + let original = [7,8,tuple,12]; let p1 = Program.to(original); let p1_as_js = p1.as_javascript(); - console.log(p1_as_js); assert.equal(original.toString(), p1_as_js.toString()); }); From eb287638ac87b58a686572dfaad4d3899db620d0 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 24 Aug 2023 20:54:49 -0700 Subject: [PATCH 124/196] Finalize new tests and test data. --- .github/workflows/npm-publish.yml | 4 + wasm/src/objects.rs | 92 ++++++++++++++++++- wasm/tests/clvm-tools-interface/.eslintignore | 2 + .../tests/clvm-tools-interface/.eslintrc.json | 31 +++++++ wasm/tests/clvm-tools-interface/.npmignore | 36 ++++++++ ...delegated_puzzle_or_hidden_puzzle.clvm.hex | 1 + .../src/lib/tests/index.test.ts | 47 +++++++++- 7 files changed, 205 insertions(+), 8 deletions(-) create mode 100644 wasm/tests/clvm-tools-interface/.eslintignore create mode 100644 wasm/tests/clvm-tools-interface/.eslintrc.json create mode 100644 wasm/tests/clvm-tools-interface/.npmignore create mode 100644 wasm/tests/clvm-tools-interface/content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 395a02866..36ac60fde 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -43,6 +43,10 @@ jobs: - name: Test wasm run: node wasm/tests/index.js + - name: Test clvm-js like wasm interface + run: | + cd wasm/tests/clvm-tools-interface && npm install && yarn test + - name: Upload npm pkg artifacts uses: actions/upload-artifact@v3 with: diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 390d1efa6..3bd701f3d 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -8,10 +8,11 @@ use std::rc::Rc; use wasm_bindgen::prelude::*; use clvmr::Allocator; -use clvm_tools_rs::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType}; +use clvm_tools_rs::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType, bi_one}; use clvm_tools_rs::classic::clvm::serialize::{SimpleCreateCLVMObject, sexp_to_stream, sexp_from_stream}; use clvm_tools_rs::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; use clvm_tools_rs::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, sha256tree, truthy}; +use clvm_tools_rs::compiler::prims::{primapply, primcons, primquote}; use clvm_tools_rs::compiler::sexp::SExp; use clvm_tools_rs::compiler::srcloc::Srcloc; @@ -23,6 +24,7 @@ const DEFAULT_CACHE_ENTRIES: usize = 1024; struct FunctionWrapperDesc { export_name: &'static str, member_name: &'static str, + varargs: bool, } #[derive(Clone)] @@ -131,65 +133,90 @@ static PROGRAM_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ FunctionWrapperDesc { export_name: "toString", member_name: "to_string_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "as_pair", member_name: "as_pair_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "listp", member_name: "listp_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "nullp", member_name: "nullp_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "as_int", member_name: "as_int_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "as_bigint", member_name: "as_bigint_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "as_bin", member_name: "as_bin_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "first", member_name: "first_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "rest", member_name: "rest_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "cons", member_name: "cons_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "run", member_name: "run_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "list_len", member_name: "list_len_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "equal_to", member_name: "equal_to_internal", + varargs: false, }, FunctionWrapperDesc { export_name: "as_javascript", member_name: "as_javascript_internal", + varargs: false, }, + FunctionWrapperDesc { + export_name: "curry", + member_name: "curry_internal", + varargs: true, + }, + FunctionWrapperDesc { + export_name: "sha256tree", + member_name: "sha256tree_internal", + varargs: false, + } ]; static TUPLE_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ FunctionWrapperDesc { export_name: "to_program", member_name: "tuple_to_program_internal", + varargs: false }, ]; @@ -260,9 +287,15 @@ fn get_program_prototype() -> Result { let program_self = js_sys::eval("Program")?; for func_wrapper_desc in PROGRAM_FUNCTIONS.iter() { + let pass_on_args = + if func_wrapper_desc.varargs { + "[args]" + } else { + "args" + }; let to_string_fun = js_sys::Function::new_with_args( "", - &format!("const t = this; return function() {{ let args = Array.prototype.slice.call(arguments); args.unshift(this); return t.{}.apply(null, args); }}", func_wrapper_desc.member_name) + &format!("const t = this; return function() {{ let args = Array.prototype.slice.call(arguments); let apply_args = {pass_on_args}; apply_args.unshift(this); return t.{}.apply(null, apply_args); }}", func_wrapper_desc.member_name) ); let to_string_final = to_string_fun.call0(&program_self)?; @@ -526,7 +559,11 @@ impl Program { })?; let result_id = get_next_id(); let new_cached_result = create_cached_sexp(result_id, modern_result)?; - finish_new_object(result_id, &new_cached_result) + let result_object = finish_new_object(result_id, &new_cached_result)?; + let cost_and_result_array = Array::new(); + cost_and_result_array.push(&JsValue::from_f64(run_result.0 as f64)); + cost_and_result_array.push(&result_object); + Ok(cost_and_result_array.into()) } #[wasm_bindgen] @@ -588,4 +625,53 @@ impl Program { let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; js_object_from_sexp(cached.modern.clone()) } + + // Ported from chia.types.blockchain_format.program in chia-blockchain. + // + // original comment: + // + // Replicates the curry function from clvm_tools, taking advantage of *args + // being a list. We iterate through args in reverse building the code to + // create a clvm list. + // + // Given arguments to a function addressable by the '1' reference in clvm + // + // fixed_args = 1 + // + // Each arg is prepended as fixed_args = (c (q . arg) fixed_args) + // + // The resulting argument list is interpreted with apply (2) + // + // (2 (1 . self) rest) + // + // Resulting in a function which places its own arguments after those + // curried in in the form of a proper list. + #[wasm_bindgen] + pub fn curry_internal(obj: &JsValue, args: Vec) -> Result { + let program_val = Program::to(obj)?; + let cacheval = js_cache_value_from_js(&program_val)?; + let program = find_cached_sexp(cacheval.entry, &cacheval.content)?; + let mut fixed_args = Rc::new(SExp::Integer(get_srcloc(), bi_one())); + + for a in args.iter().rev() { + let argval = Program::to(a)?; + let a_cacheval = js_cache_value_from_js(&argval)?; + let a_cached = find_cached_sexp(a_cacheval.entry, &a_cacheval.content)?; + fixed_args = Rc::new(primcons( + get_srcloc(), + Rc::new(primquote(get_srcloc(), a_cached.modern.clone())), + fixed_args + )); + } + + let result = Rc::new(primapply( + get_srcloc(), + Rc::new(primquote(get_srcloc(), program.modern.clone())), + fixed_args + )); + + let new_id = get_next_id(); + let new_cached = create_cached_sexp(new_id, result)?; + finish_new_object(new_id, &new_cached) + } } diff --git a/wasm/tests/clvm-tools-interface/.eslintignore b/wasm/tests/clvm-tools-interface/.eslintignore new file mode 100644 index 000000000..2c7ea48ea --- /dev/null +++ b/wasm/tests/clvm-tools-interface/.eslintignore @@ -0,0 +1,2 @@ +build/* +/**/*.d.ts \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/.eslintrc.json b/wasm/tests/clvm-tools-interface/.eslintrc.json new file mode 100644 index 000000000..d614b0b2f --- /dev/null +++ b/wasm/tests/clvm-tools-interface/.eslintrc.json @@ -0,0 +1,31 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "modules": true, + "experimentalObjectRestSpread": true + } + }, + "plugins": ["@typescript-eslint"], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "rules": { + "comma-dangle": 0, + "no-unused-vars": "warn", + "no-unexpected-multiline": "warn", + "prefer-const": "warn", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-var-requires": "off" + }, + "settings": {}, + "env": { + "browser": true, + "node": true, + "jasmine": true, + "jest": true, + "es6": true + } +} diff --git a/wasm/tests/clvm-tools-interface/.npmignore b/wasm/tests/clvm-tools-interface/.npmignore new file mode 100644 index 000000000..d36841e97 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/.npmignore @@ -0,0 +1,36 @@ +# dependencies +/node_modules + +# testing +/tests +/coverage + +# docs +/docs + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local +/.github +/demo +.esdoc.json + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Development folders and files +public +src +scripts +config +.travis.yml +CHANGELOG.md +README.md +.eslintignore +.eslintrc.json +webpack.config.js +babel.config.js \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex b/wasm/tests/clvm-tools-interface/content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex new file mode 100644 index 000000000..4d96fe6ce --- /dev/null +++ b/wasm/tests/clvm-tools-interface/content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index b18f13312..626d11b41 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -1,3 +1,5 @@ +import * as fs from 'fs'; +import { resolve } from 'path'; import * as assert from 'assert'; import * as bls_loader from 'bls-signatures'; const {h, t, Program} = require('../../../../../pkg/clvm_tools_wasm'); @@ -59,7 +61,7 @@ it('Has as_int', async () => { assert.equal(int_value, 7); try { non_int_value = Program.to([7,13]).as_int(); - assert.fail(); + assert.fail(true); } catch (e) { assert.equal(e.toString(), "not a number"); } @@ -70,7 +72,7 @@ it('Has as_bigint', async () => { assert.equal(int_value, 10000000000000000000000n); try { non_int_value = Program.to([7,13]).as_bigint(); - assert.fail(); + assert.fail(true); } catch (e) { assert.equal(e.toString(), "not a number"); } @@ -82,13 +84,13 @@ it('Has first and rest', async () => { assert.equal(test_list.rest().toString(), 'ff0dff11ff1780'); try { Program.to([]).first(); - assert.fail(); + assert.fail(true); } catch (e) { assert.equal(e.toString(), "not a cons"); } try { Program.to([]).rest(); - assert.fail(); + assert.fail(true); } catch (e) { assert.equal(e.toString(), "not a cons"); } @@ -145,5 +147,40 @@ it('Has as_javascript', async () => { it('Has run', async () => { let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); let args = Program.to([13]); - assert.equal(program.run(args).toString(), '8200a8'); + const [cost, run_result] = program.run(args); + assert.equal(run_result.toString(), '8200a8'); + assert.equal(cost, 2658); +}); + +it('Has curry', async () => { + let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); + let program_with_arg = program.curry(Program.to(13)); + const [cost, run_result] = program_with_arg.run(Program.to([])); + assert.equal(run_result.toString(), '8200a8'); + assert.equal(cost, 2884); +}); + +export class ChiaExample { + constructor(MOD) { + this.MOD = MOD; + } + public puzzle_for_synthetic_public_key(synthetic_public_key: G1Element): Program { + return this.MOD.curry(synthetic_public_key); + } +} + +it('works as expected in context', async () => { + let bls = await bls_loader.default(); + const program_text = fs.readFileSync(resolve(__dirname, '../../../content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex'),'utf-8'); + const MOD: Program = Program.from_hex(program_text); + let ce = new ChiaExample(MOD); + let sk = bls.AugSchemeMPL.key_gen([ + 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, 19, 18, 12, 89, 6, 220, + 18, 102, 58, 209, 82, 12, 62, 89, 110, 182, 9, 44, 20, 254, 22 + ]); + let pk = bls.AugSchemeMPL.sk_to_g1(sk); + // pk bytes 86243290bbcbfd9ae75bdece7981965350208eb5e99b04d5cd24e955ada961f8c0a162dee740be7bdc6c3c0613ba2eb1 + // Expected puzzle hash = 30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507 + let target_puzzle = ce.puzzle_for_synthetic_public_key(pk); + assert.equal(target_puzzle.sha256tree().toString(), h('30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507').toString()); }); From 618331d0ce4fe66672fc73ea3ce91d28176ced60 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 24 Aug 2023 21:16:54 -0700 Subject: [PATCH 125/196] Add an empty index.js ... this test is for the wasm, but it's from project stationary that contained a library --- wasm/tests/clvm-tools-interface/src/lib/index.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 wasm/tests/clvm-tools-interface/src/lib/index.js diff --git a/wasm/tests/clvm-tools-interface/src/lib/index.js b/wasm/tests/clvm-tools-interface/src/lib/index.js new file mode 100644 index 000000000..e69de29bb From aa13c1def49f68c5fbb9c574e5da0327936d7aee Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 24 Aug 2023 21:32:11 -0700 Subject: [PATCH 126/196] change name --- wasm/tests/clvm-tools-interface/src/lib/{index.js => index.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename wasm/tests/clvm-tools-interface/src/lib/{index.js => index.ts} (100%) diff --git a/wasm/tests/clvm-tools-interface/src/lib/index.js b/wasm/tests/clvm-tools-interface/src/lib/index.ts similarity index 100% rename from wasm/tests/clvm-tools-interface/src/lib/index.js rename to wasm/tests/clvm-tools-interface/src/lib/index.ts From 067b8de30baa81f440848f0454d9f9ff929b6cdf Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 29 Aug 2023 14:38:47 -0700 Subject: [PATCH 127/196] WIP fixing renaming in the stack involving a lambda and captures --- src/compiler/evaluate.rs | 55 ++++++++++++++++++++++++++++++++-- src/tests/compiler/compiler.rs | 43 ++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 2a437888a..4c6487719 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -667,6 +667,27 @@ pub fn eval_dont_expand_let(inline_hint: &Option) -> bool { matches!(inline_hint, Some(LetFormInlineHint::NonInline(_))) } +fn build_capture_bindings( + capture_args: Rc, + capture_data: Rc, +) -> Result>, CompileErr> { + let mut capture_map = HashMap::new(); + let formed_args = decons_args(capture_data.clone()); + create_argument_captures( + &mut capture_map, + &formed_args, + capture_args + )?; + Ok(capture_map.into_iter().map(|(k,v)| { + Rc::new(Binding { + loc: capture_data.loc(), + nl: capture_data.loc(), + pattern: BindingPattern::Name(k), + body: v + }) + }).collect()) +} + impl<'info> Evaluator { pub fn new( opts: Rc, @@ -1194,11 +1215,39 @@ impl<'info> Evaluator { only_inline, )?; + // Perform replacements by wrapping the body in a let binding for all + // the captures. + let capture_bindings = build_capture_bindings( + ldata.capture_args.clone(), + new_captures, + )?; + + if capture_bindings.is_empty() { + return Ok(Rc::new(BodyForm::Lambda(Box::new(ldata.clone())))); + } + + let new_lambda_body = + Rc::new(BodyForm::Let( + LetFormKind::Parallel, + Box::new(LetData { + loc: ldata.loc.clone(), + kw: None, + inline_hint: None, + bindings: capture_bindings, + body: ldata.body.clone(), + }) + )); + // This is the first part of eta-conversion. - Ok(Rc::new(BodyForm::Lambda(Box::new(LambdaData { - captures: new_captures, + let reified_lambda = Rc::new(BodyForm::Lambda(Box::new(LambdaData { + args: ldata.args.clone(), + capture_args: Rc::new(SExp::Nil(ldata.loc.clone())), + captures: Rc::new(BodyForm::Value(SExp::Nil(ldata.loc.clone()))), + body: new_lambda_body, ..ldata.clone() - })))) + }))); + + Ok(reified_lambda) } fn get_function(&self, name: &[u8]) -> Option> { diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index c377d0f61..f4eb86f7b 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1938,3 +1938,46 @@ fn test_let_in_rest_1() { let res = run_string(&prog, &"(3 2)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "108"); } + +#[test] +fn test_lambda_override_name_arg_let_capture() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) + (lambda ((& overridden) z) (+ overridden z)) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "50"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_let_in_lambda() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) + (lambda ((& overridden) z) + (let + ((z (+ 123 z))) + (+ overridden z) + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "167"); +} From 981744a501aa500725cefef616842e3616cebad0 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 31 Aug 2023 09:57:08 -0700 Subject: [PATCH 128/196] Add test for tricky renaming and support in evaluator for more durable lambda use --- src/compiler/evaluate.rs | 113 +++++++++++++++++++-------------- src/compiler/rename.rs | 5 +- src/tests/compiler/compiler.rs | 2 +- 3 files changed, 70 insertions(+), 50 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 4c6487719..61994e938 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -9,7 +9,7 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::run; +use crate::compiler::clvm::{run, truthy}; use crate::compiler::codegen::{codegen, hoist_assign_form}; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ @@ -667,25 +667,25 @@ pub fn eval_dont_expand_let(inline_hint: &Option) -> bool { matches!(inline_hint, Some(LetFormInlineHint::NonInline(_))) } -fn build_capture_bindings( - capture_args: Rc, - capture_data: Rc, -) -> Result>, CompileErr> { - let mut capture_map = HashMap::new(); - let formed_args = decons_args(capture_data.clone()); - create_argument_captures( - &mut capture_map, - &formed_args, - capture_args - )?; - Ok(capture_map.into_iter().map(|(k,v)| { - Rc::new(Binding { - loc: capture_data.loc(), - nl: capture_data.loc(), - pattern: BindingPattern::Name(k), - body: v - }) - }).collect()) +pub fn filter_capture_args(args: Rc, name_map: &HashMap, Rc>) -> Rc { + match args.borrow() { + SExp::Cons(l,a,b) => { + let a_filtered = filter_capture_args(a.clone(), name_map); + let b_filtered = filter_capture_args(b.clone(), name_map); + if !truthy(a_filtered.clone()) && !truthy(b_filtered.clone()) { + return Rc::new(SExp::Nil(l.clone())); + } + Rc::new(SExp::Cons(l.clone(),a_filtered,b_filtered)) + } + SExp::Atom(l,n) => { + if name_map.contains_key(n) { + Rc::new(SExp::Nil(l.clone())) + } else { + args + } + } + _ => Rc::new(SExp::Nil(args.loc())) + } } impl<'info> Evaluator { @@ -819,6 +819,7 @@ impl<'info> Evaluator { only_inline: bool, ) -> Result, CompileErr> { let mut lambda_env = env.clone(); + // Finish eta-expansion. // We're carrying an enriched environment which we can use to enrich @@ -1205,49 +1206,67 @@ impl<'info> Evaluator { ldata: &LambdaData, only_inline: bool, ) -> Result, CompileErr> { + if !truthy(ldata.capture_args.clone()) { + return Ok(Rc::new(BodyForm::Lambda(Box::new(ldata.clone())))); + } + // Rewrite the captures based on what we know at the call site. let new_captures = self.shrink_bodyform_visited( allocator, visited, - prog_args, + prog_args.clone(), env, ldata.captures.clone(), only_inline, )?; - // Perform replacements by wrapping the body in a let binding for all - // the captures. - let capture_bindings = build_capture_bindings( - ldata.capture_args.clone(), - new_captures, + // Break up and make binding map. + let deconsed_args = decons_args(new_captures.clone()); + let mut arg_captures = HashMap::new(); + create_argument_captures( + &mut arg_captures, + &deconsed_args, + ldata.capture_args.clone() )?; - if capture_bindings.is_empty() { - return Ok(Rc::new(BodyForm::Lambda(Box::new(ldata.clone())))); + // Filter out elements that are not interpretable yet. + let mut interpretable_captures = HashMap::new(); + for (n,v) in arg_captures.iter() { + if let Ok(_) = dequote(v.loc(), v.clone()) { + // This capture has already been made into a literal. + // We will substitute it in the lambda body and remove it + // from the capture set. + interpretable_captures.insert(n.clone(), v.clone()); + } } - let new_lambda_body = - Rc::new(BodyForm::Let( - LetFormKind::Parallel, - Box::new(LetData { - loc: ldata.loc.clone(), - kw: None, - inline_hint: None, - bindings: capture_bindings, - body: ldata.body.clone(), - }) - )); + let combined_args = Rc::new(SExp::Cons( + ldata.loc.clone(), + ldata.capture_args.clone(), + ldata.args.clone() + )); - // This is the first part of eta-conversion. - let reified_lambda = Rc::new(BodyForm::Lambda(Box::new(LambdaData { + // Eliminate the captures via beta substituion. + let simplified_body = self.shrink_bodyform_visited( + allocator, + visited, + combined_args.clone(), + &interpretable_captures, + ldata.body.clone(), + only_inline + )?; + + let new_capture_args = filter_capture_args( + ldata.capture_args.clone(), + &interpretable_captures, + ); + Ok(Rc::new(BodyForm::Lambda(Box::new(LambdaData { args: ldata.args.clone(), - capture_args: Rc::new(SExp::Nil(ldata.loc.clone())), - captures: Rc::new(BodyForm::Value(SExp::Nil(ldata.loc.clone()))), - body: new_lambda_body, + capture_args: new_capture_args, + captures: new_captures, + body: simplified_body, ..ldata.clone() - }))); - - Ok(reified_lambda) + })))) } fn get_function(&self, name: &[u8]) -> Option> { diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 594e228fb..587c88a13 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -249,11 +249,12 @@ fn rename_in_bodyform(namemap: &HashMap, Vec>, b: Rc) -> B Rc::new(rename_in_bodyform(namemap, ldata.captures.clone())); let renamed_capture_outputs = rename_in_cons(namemap, ldata.capture_args.clone(), false); - let renamed_body = rename_in_bodyform(namemap, ldata.body.clone()); + let renamed_body = Rc::new(rename_args_bodyform(ldata.body.borrow())); + let outer_renamed_body = rename_in_bodyform(namemap, renamed_body); BodyForm::Lambda(Box::new(LambdaData { captures: renamed_capture_inputs, capture_args: renamed_capture_outputs, - body: Rc::new(renamed_body), + body: Rc::new(outer_renamed_body), ..*ldata.clone() })) } diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index f4eb86f7b..7660b3e0e 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1979,5 +1979,5 @@ fn test_lambda_override_name_arg_let_with_let_in_lambda() { )"} .to_string(); let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); - assert_eq!(res.to_string(), "167"); + assert_eq!(res.to_string(), "173"); } From 8ab9e1757fdcb88884eac1be1d083589edb72b4e Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 6 Sep 2023 09:28:15 -0700 Subject: [PATCH 129/196] Move in the right direction --- src/compiler/frontend.rs | 15 +------ src/compiler/rename.rs | 35 +++++++++++++--- src/tests/compiler/compiler.rs | 73 +++++++++++++++++++++++++++++++++- 3 files changed, 103 insertions(+), 20 deletions(-) diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 81de7feac..326288552 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -11,7 +11,7 @@ use crate::compiler::comptypes::{ }; use crate::compiler::lambda::handle_lambda; use crate::compiler::preprocessor::preprocess; -use crate::compiler::rename::{rename_assign_bindings, rename_children_compileform}; +use crate::compiler::rename::rename_children_compileform; use crate::compiler::sexp::{decode_string, enlist, SExp}; use crate::compiler::srcloc::Srcloc; use crate::util::u8_from_number; @@ -299,10 +299,6 @@ pub fn make_provides_set(provides_set: &mut HashSet>, body_sexp: Rc) -> bool { - opts.dialect().stepping.unwrap_or(0) > 22 -} - fn handle_assign_form( opts: Rc, l: Srcloc, @@ -346,19 +342,12 @@ fn handle_assign_form( })); } - let mut compiled_body = compile_bodyform(opts.clone(), Rc::new(v[v.len() - 1].clone()))?; + let compiled_body = compile_bodyform(opts.clone(), Rc::new(v[v.len() - 1].clone()))?; // We don't need to do much if there were no bindings. if bindings.is_empty() { return Ok(compiled_body); } - if at_or_above_23(opts.clone()) { - let (new_compiled_body, new_bindings) = - rename_assign_bindings(&l, &bindings, Rc::new(compiled_body))?; - compiled_body = new_compiled_body; - bindings = new_bindings; - }; - // Return a precise representation of this assign while storing up the work // we did breaking it down. Ok(BodyForm::Let( diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 74d55da6e..0091f76e0 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -8,7 +8,7 @@ use crate::compiler::comptypes::{ DefmacData, DefunData, HelperForm, LambdaData, LetData, LetFormKind, }; use crate::compiler::gensym::gensym; -use crate::compiler::sexp::SExp; +use crate::compiler::sexp::{SExp, decode_string}; use crate::compiler::srcloc::Srcloc; use crate::util::TopoSortItem; @@ -166,7 +166,7 @@ pub fn rename_assign_bindings( let sorted_bindings = toposort_assign_bindings(l, bindings)?; let mut renames = HashMap::new(); // Process in reverse order so we rename from inner to outer. - let bindings_to_rename: Vec> = sorted_bindings.iter().rev().cloned().collect(); + let bindings_to_rename: Vec> = sorted_bindings.iter().cloned().collect(); let renamed_bindings = map_m_reverse( |item: &TopoSortItem<_>| -> Result, CompileErr> { let b: &Binding = bindings[item.index].borrow(); @@ -175,6 +175,9 @@ pub fn rename_assign_bindings( for (name, renamed) in new_names.iter() { renames.insert(name.clone(), renamed.clone()); } + let renames_vec: Vec<_> = renames.iter().map(|(k,v)| (decode_string(k), decode_string(v))).collect(); + eprintln!("renames from here {}: {:?}", p, renames_vec); + eprintln!("this binding {}", b.to_sexp()); Ok(Rc::new(Binding { pattern: BindingPattern::Complex(rename_in_cons(&renames, p.clone(), false)), body: Rc::new(rename_in_bodyform(&renames, b.body.clone())?), @@ -343,7 +346,19 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { )) } - BodyForm::Let(LetFormKind::Assign, _letdata) => Ok(b.clone()), + BodyForm::Let(LetFormKind::Assign, letdata) => { + let (new_compiled_body, new_bindings) = + rename_assign_bindings(&letdata.loc, &letdata.bindings, letdata.body.clone())?; + for b in new_bindings.iter() { + eprintln!("- {}", b.to_sexp()); + } + eprintln!("new_compiled {}", new_compiled_body.to_sexp()); + Ok(BodyForm::Let(LetFormKind::Assign, Box::new(LetData { + body: Rc::new(new_compiled_body), + bindings: new_bindings, + ..*letdata.clone() + }))) + } BodyForm::Quoted(e) => Ok(BodyForm::Quoted(e.clone())), BodyForm::Value(v) => Ok(BodyForm::Value(v.clone())), @@ -363,7 +378,13 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { Ok(BodyForm::Call(l.clone(), new_vs, new_tail)) } BodyForm::Mod(l, program) => Ok(BodyForm::Mod(l.clone(), program.clone())), - BodyForm::Lambda(ldata) => Ok(BodyForm::Lambda(ldata.clone())), + BodyForm::Lambda(ldata) => { + let new_body = rename_args_bodyform(ldata.body.borrow())?; + Ok(BodyForm::Lambda(Box::new(LambdaData { + body: Rc::new(new_body), + ..*ldata.clone() + }))) + }, } } @@ -479,13 +500,15 @@ fn rename_in_compileform( pub fn rename_children_compileform(c: &CompileForm) -> Result { let local_renamed_helpers = map_m(&rename_args_helperform, &c.helpers)?; let local_renamed_body = rename_args_bodyform(c.exp.borrow())?; - Ok(CompileForm { + let res = CompileForm { loc: c.loc.clone(), args: c.args.clone(), include_forms: c.include_forms.clone(), helpers: local_renamed_helpers, exp: Rc::new(local_renamed_body), - }) + }; + eprintln!("rename {}", res.to_sexp()); + Ok(res) } pub fn rename_args_compileform(c: &CompileForm) -> Result { diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 7660b3e0e..b15695fca 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1959,7 +1959,7 @@ fn test_lambda_override_name_arg_let_capture() { } #[test] -fn test_lambda_override_name_arg_let_with_let_in_lambda() { +fn test_lambda_override_name_arg_let_with_let_in_lambda_1() { let prog = indoc! {" (mod (X) (include *standard-cl-21*) @@ -1981,3 +1981,74 @@ fn test_lambda_override_name_arg_let_with_let_in_lambda() { let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "173"); } + +#[test] +fn test_lambda_override_name_arg_let_with_let_in_lambda_2() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) + (lambda ((& overridden) z) + (let + ((overridden (+ 123 overridden))) + (+ overridden z) + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "173"); +} + +#[test] +fn test_lambda_override_name_arg_assign_with_assign_in_lambda_1() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (Z) + (assign overridden (* 3 Z) + (lambda ((& overridden) z) + (let + ((z (+ 123 z))) + (+ overridden z) + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "173"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_assign_in_lambda_1() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) z) ;; overridden = 33 + (assign overridden (+ 123 z) ;; overridden = 17 + 123 = 140 + (+ overridden z) ;; 157 + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "157"); +} From bacf83c83f70e0cf33860056d2fbecbac2e52840 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 6 Sep 2023 09:31:34 -0700 Subject: [PATCH 130/196] remove spam --- src/compiler/rename.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 0091f76e0..f708b02fa 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -176,8 +176,6 @@ pub fn rename_assign_bindings( renames.insert(name.clone(), renamed.clone()); } let renames_vec: Vec<_> = renames.iter().map(|(k,v)| (decode_string(k), decode_string(v))).collect(); - eprintln!("renames from here {}: {:?}", p, renames_vec); - eprintln!("this binding {}", b.to_sexp()); Ok(Rc::new(Binding { pattern: BindingPattern::Complex(rename_in_cons(&renames, p.clone(), false)), body: Rc::new(rename_in_bodyform(&renames, b.body.clone())?), @@ -349,10 +347,6 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { BodyForm::Let(LetFormKind::Assign, letdata) => { let (new_compiled_body, new_bindings) = rename_assign_bindings(&letdata.loc, &letdata.bindings, letdata.body.clone())?; - for b in new_bindings.iter() { - eprintln!("- {}", b.to_sexp()); - } - eprintln!("new_compiled {}", new_compiled_body.to_sexp()); Ok(BodyForm::Let(LetFormKind::Assign, Box::new(LetData { body: Rc::new(new_compiled_body), bindings: new_bindings, @@ -500,15 +494,13 @@ fn rename_in_compileform( pub fn rename_children_compileform(c: &CompileForm) -> Result { let local_renamed_helpers = map_m(&rename_args_helperform, &c.helpers)?; let local_renamed_body = rename_args_bodyform(c.exp.borrow())?; - let res = CompileForm { + Ok(CompileForm { loc: c.loc.clone(), args: c.args.clone(), include_forms: c.include_forms.clone(), helpers: local_renamed_helpers, exp: Rc::new(local_renamed_body), - }; - eprintln!("rename {}", res.to_sexp()); - Ok(res) + }) } pub fn rename_args_compileform(c: &CompileForm) -> Result { From 3ed70de2479666b137e49816d2fe096531bec6f9 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 6 Sep 2023 09:52:12 -0700 Subject: [PATCH 131/196] More renames working too --- src/compiler/rename.rs | 3 +-- src/tests/compiler/compiler.rs | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index f708b02fa..3d77fc89c 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -8,7 +8,7 @@ use crate::compiler::comptypes::{ DefmacData, DefunData, HelperForm, LambdaData, LetData, LetFormKind, }; use crate::compiler::gensym::gensym; -use crate::compiler::sexp::{SExp, decode_string}; +use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; use crate::util::TopoSortItem; @@ -175,7 +175,6 @@ pub fn rename_assign_bindings( for (name, renamed) in new_names.iter() { renames.insert(name.clone(), renamed.clone()); } - let renames_vec: Vec<_> = renames.iter().map(|(k,v)| (decode_string(k), decode_string(v))).collect(); Ok(Rc::new(Binding { pattern: BindingPattern::Complex(rename_in_cons(&renames, p.clone(), false)), body: Rc::new(rename_in_bodyform(&renames, b.body.clone())?), diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index b15695fca..67160f705 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -2052,3 +2052,28 @@ fn test_lambda_override_name_arg_let_with_assign_in_lambda_1() { let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "157"); } + +#[test] +fn test_lambda_override_name_arg_let_with_assign_twice_in_lambda() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (assign + overridden (+ 123 z) ;; overridden = 123 + 17 = 140 + y (+ 191 z overridden) ;; y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 505 + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "505"); +} From 64bc156292ec8d4b429b1df26b77586fa38d9695 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 6 Sep 2023 15:20:39 -0700 Subject: [PATCH 132/196] Fix downstream renaming in let*, which was a bug --- src/compiler/rename.rs | 15 ++++--- src/tests/compiler/compiler.rs | 74 ++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 766ce0ba6..3dc573834 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -298,11 +298,13 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { BodyForm::Let(LetFormKind::Sequential, letdata) => { // Renaming a sequential let is exactly as if the bindings were // nested in separate parallel lets. - rename_args_bodyform(&desugar_sequential_let_bindings( + let res = rename_args_bodyform(&desugar_sequential_let_bindings( &letdata.bindings, letdata.body.borrow(), letdata.bindings.len(), - )) + ))?; + eprintln!("sequentialized rename {}", res.to_sexp()); + Ok(res) } BodyForm::Let(LetFormKind::Parallel, letdata) => { @@ -332,15 +334,18 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { }, &new_renamed_bindings, )?; - let locally_renamed_body = rename_in_bodyform(&local_namemap, letdata.body.clone())?; - Ok(BodyForm::Let( + let args_renamed = rename_args_bodyform(letdata.body.borrow())?; + let locally_renamed_body = rename_in_bodyform(&local_namemap, Rc::new(args_renamed))?; + let new_form = BodyForm::Let( LetFormKind::Parallel, Box::new(LetData { bindings: new_bindings, body: Rc::new(locally_renamed_body), ..*letdata.clone() }), - )) + ); + eprintln!("{} renamed to {}", b.to_sexp(), new_form.to_sexp()); + Ok(new_form) } BodyForm::Let(LetFormKind::Assign, letdata) => { diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 67160f705..03d5f17cd 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -2053,6 +2053,29 @@ fn test_lambda_override_name_arg_let_with_assign_in_lambda_1() { assert_eq!(res.to_string(), "157"); } +#[test] +fn test_lambda_override_name_arg_let_with_let_in_lambda_3() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) z) ;; overridden = 33 + (let ((overridden (+ 123 z))) ;; overridden = 17 + 123 = 140 + (+ overridden z) ;; 157 + ) + ) + ) + ) + + (a (F X) (list 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "157"); +} + #[test] fn test_lambda_override_name_arg_let_with_assign_twice_in_lambda() { let prog = indoc! {" @@ -2077,3 +2100,54 @@ fn test_lambda_override_name_arg_let_with_assign_twice_in_lambda() { let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "505"); } + +#[test] +fn test_lambda_override_name_arg_let_with_let_twice_in_lambda() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (let + ((overridden (+ 123 z))) ;; overridden = 123 + 17 = 140 + (let ((y (+ 191 z overridden))) ;; y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 505 + ) + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "505"); +} + +#[test] +fn test_lambda_override_name_arg_let_with_let_star_twice_in_lambda() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (let* + ((overridden (+ 123 z)) ;; overridden = 123 + 17 = 140 + (y (+ 191 z overridden))) ;; y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 505 + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "505"); +} From f5c07f9157b775701c2b9d9731b0ac565f191cec Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 6 Sep 2023 16:24:52 -0700 Subject: [PATCH 133/196] Add test with let in binding --- src/tests/compiler/compiler.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 03d5f17cd..a2da13469 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -2151,3 +2151,27 @@ fn test_lambda_override_name_arg_let_with_let_star_twice_in_lambda() { let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "505"); } + +#[test] +fn test_lambda_let_override_in_binding() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (let + ((y (+ 191 z (let ((overridden (+ 123 z))) overridden)))) ;; overridden = 123 + 17 = 140, y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 33 + 17 + 348 = 398 + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); + assert_eq!(res.to_string(), "398"); +} From 1d4ba0429bc1a98a3029cf36bdbbf74ad1262176 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 7 Sep 2023 07:34:54 -0700 Subject: [PATCH 134/196] despam --- src/compiler/rename.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 3dc573834..1c75c44a3 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -298,13 +298,11 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { BodyForm::Let(LetFormKind::Sequential, letdata) => { // Renaming a sequential let is exactly as if the bindings were // nested in separate parallel lets. - let res = rename_args_bodyform(&desugar_sequential_let_bindings( + rename_args_bodyform(&desugar_sequential_let_bindings( &letdata.bindings, letdata.body.borrow(), letdata.bindings.len(), - ))?; - eprintln!("sequentialized rename {}", res.to_sexp()); - Ok(res) + ) } BodyForm::Let(LetFormKind::Parallel, letdata) => { @@ -344,7 +342,6 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { ..*letdata.clone() }), ); - eprintln!("{} renamed to {}", b.to_sexp(), new_form.to_sexp()); Ok(new_form) } From d058b23da640368e7b87fdc2dc2d43846d33efab Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 7 Sep 2023 07:35:39 -0700 Subject: [PATCH 135/196] opps --- src/compiler/rename.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 1c75c44a3..a6d861ff4 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -302,7 +302,7 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { &letdata.bindings, letdata.body.borrow(), letdata.bindings.len(), - ) + )) } BodyForm::Let(LetFormKind::Parallel, letdata) => { From 6a07de4914795be058021329e944e8cd687e1fd8 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 7 Sep 2023 09:02:39 -0700 Subject: [PATCH 136/196] Add some more infra to allow testing of renaming. Hadn't thought of good ways to do it before now --- src/compiler/frontend.rs | 2 +- src/compiler/rename.rs | 11 ++++-- src/tests/compiler/compiler.rs | 64 ++++++++++++++++++++++++++++++++-- src/tests/compiler/evaluate.rs | 13 ++++--- 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 326288552..ad46f8ed8 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -16,7 +16,7 @@ use crate::compiler::sexp::{decode_string, enlist, SExp}; use crate::compiler::srcloc::Srcloc; use crate::util::u8_from_number; -fn collect_used_names_sexp(body: Rc) -> Vec> { +pub fn collect_used_names_sexp(body: Rc) -> Vec> { match body.borrow() { SExp::Atom(_, name) => vec![name.to_vec()], SExp::Cons(_, head, tail) => { diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index a6d861ff4..808acfb75 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -36,7 +36,7 @@ fn rename_in_qq(namemap: &HashMap, Vec>, body: Rc) -> Rc } /* Given a cons cell, rename occurrences of oldname to newname */ -fn rename_in_cons( +pub fn rename_in_cons( namemap: &HashMap, Vec>, body: Rc, qq_handling: bool, @@ -377,9 +377,16 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { } BodyForm::Mod(l, program) => Ok(BodyForm::Mod(l.clone(), program.clone())), BodyForm::Lambda(ldata) => { + let mut own_args = HashMap::new(); + for (n,v) in invent_new_names_sexp(ldata.args.clone()).iter() { + own_args.insert(n.clone(), v.clone()); + } + let new_args = rename_in_cons(&own_args, ldata.args.clone(), false); let new_body = rename_args_bodyform(ldata.body.borrow())?; + let renamed_with_own_args = rename_in_bodyform(&own_args, Rc::new(new_body))?; Ok(BodyForm::Lambda(Box::new(LambdaData { - body: Rc::new(new_body), + args: new_args, + body: Rc::new(renamed_with_own_args), ..*ldata.clone() }))) }, diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index a2da13469..133a52e08 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeSet, HashMap}; use std::rc::Rc; use clvm_rs::allocator::Allocator; @@ -7,8 +7,10 @@ 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::frontend::{collect_used_names_sexp, frontend}; +use crate::compiler::rename::rename_in_cons; use crate::compiler::runtypes::RunFailure; -use crate::compiler::sexp::{parse_sexp, SExp}; +use crate::compiler::sexp::{decode_string, parse_sexp, SExp}; use crate::compiler::srcloc::Srcloc; const TEST_TIMEOUT: usize = 1000000; @@ -62,6 +64,29 @@ pub fn run_string(content: &String, args: &String) -> Result, CompileEr run_string_maybe_opt(content, args, false) } +// Given some renaming that leaves behind gensym style names with _$_ in them, +// order them and use a locally predictable renaming scheme to give them a final +// test checkable value. +pub fn squash_name_differences(in_sexp: Rc) -> Result, String> { + let found_names_set: BTreeSet<_> = collect_used_names_sexp(in_sexp.clone()).into_iter().filter(|n| n.contains(&b'$')).collect(); + let mut found_names_progression = b'A'; + let mut replacement_map = HashMap::new(); + for found_name in found_names_set.iter() { + if let Some(located_dollar_part) = found_name.iter().position(|x| *x == b'$') { + let mut new_name: Vec = found_name.iter().take(located_dollar_part + 2).copied().collect(); + new_name.push(found_names_progression); + found_names_progression += 1; + replacement_map.insert(found_name.clone(), new_name); + } else { + return Err(decode_string(&found_name)); + } + } + if replacement_map.len() != found_names_set.len() { + return Err(format!("mismatched lengths {replacement_map:?} vs {found_names_set:?}")); + } + Ok(rename_in_cons(&replacement_map, in_sexp, false)) +} + /* // Upcoming support for extra optimization (WIP) fn run_string_opt(content: &String, args: &String) -> Result, CompileErr> { run_string_maybe_opt(content, args, true) @@ -2175,3 +2200,38 @@ fn test_lambda_let_override_in_binding() { let res = run_string(&prog, &"(11)".to_string()).expect("should compile and run"); assert_eq!(res.to_string(), "398"); } + +#[test] +fn test_rename_in_compileform_simple() { + let prog = indoc! {" +(mod (X) + (include *standard-cl-21*) + + (defun F (overridden) + (let ((overridden (* 3 overridden))) ;; overridden = 33 + (lambda ((& overridden) y z) ;; overridden = 33 + (let + ((y (+ 191 z (let ((overridden (+ 123 z))) overridden)))) ;; overridden = 123 + 17 = 140, y = 191 + 17 + 140 = 348 + (+ overridden z y) ;; 33 + 17 + 348 = 398 + ) + ) + ) + ) + + (a (F X) (list 13 17)) + )"} + .to_string(); + // Note: renames use gensym so they're unique but not spot predictable. + // + // We'll rename them in detection order to a specific set of names and should + // get for F: + // + let desired_outcome = "(defun F (overridden_$_A) (let ((overridden_$_B (* 3 overridden_$_A))) (lambda ((& overridden_$_B) y_$_D z_$_F) (let ((y_$_E (+ 191 z_$_F (let ((overridden_$_C (+ 123 z_$_F))) overridden_$_C)))) (+ overridden_$_B z_$_F y_$_E)))))"; + // + let parsed = parse_sexp(Srcloc::start("*test*"), prog.bytes()).expect("should parse"); + let opts: Rc = Rc::new(DefaultCompilerOpts::new(&"*test*".to_string())); + let compiled = frontend(opts, &parsed).expect("should compile"); + let helper_f: Vec<_> = compiled.helpers.iter().filter(|f| f.name() == b"F").collect(); + let renamed_helperform = squash_name_differences(helper_f[0].to_sexp()).expect("should rename"); + assert_eq!(renamed_helperform.to_string(), desired_outcome); +} diff --git a/src/tests/compiler/evaluate.rs b/src/tests/compiler/evaluate.rs index 52ae2d9ca..f2df4a391 100644 --- a/src/tests/compiler/evaluate.rs +++ b/src/tests/compiler/evaluate.rs @@ -14,12 +14,14 @@ use crate::compiler::srcloc::Srcloc; use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::util::ErrInto; +use crate::tests::compiler::compiler::squash_name_differences; + fn shrink_expr_from_string(s: String) -> Result { let mut allocator = Allocator::new(); let runner = Rc::new(DefaultProgramRunner::new()); let opts = Rc::new(DefaultCompilerOpts::new(&"*program*".to_string())); let loc = Srcloc::start(&"*program*".to_string()); - parse_sexp(loc.clone(), s.bytes()) + let result = parse_sexp(loc.clone(), s.bytes()) .err_into() .and_then(|parsed_program| { return frontend(opts.clone(), &parsed_program); @@ -34,8 +36,10 @@ fn shrink_expr_from_string(s: String) -> Result { false, Some(EVAL_STACK_LIMIT), ); - }) - .map(|result| result.to_sexp().to_string()) + })?; + + let result_sexp = squash_name_differences(result.to_sexp()).map_err(|e| CompileErr(loc.clone(), e))?; + Ok(result_sexp.to_string()) } #[test] @@ -121,9 +125,10 @@ fn test_simple_fe_opt_compile_1() { #[test] fn test_lambda_eval_1() { + assert_eq!( shrink_expr_from_string("(lambda (X) (+ X 1))".to_string()).unwrap(), - "(lambda (X) (+ X 1))".to_string() + "(lambda (X_$_A) (+ X_$_A 1))".to_string() ); } From 40322cf3936c0e40217d5e1543424efcb5c5797c Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 7 Sep 2023 09:04:37 -0700 Subject: [PATCH 137/196] Add more testing for renaming around let lambda and assign --- src/compiler/evaluate.rs | 24 +++++++++++------------- src/compiler/rename.rs | 4 ++-- src/tests/compiler/compiler.rs | 21 +++++++++++++++++---- src/tests/compiler/evaluate.rs | 4 ++-- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 61994e938..8e8f4a9a3 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -669,22 +669,22 @@ pub fn eval_dont_expand_let(inline_hint: &Option) -> bool { pub fn filter_capture_args(args: Rc, name_map: &HashMap, Rc>) -> Rc { match args.borrow() { - SExp::Cons(l,a,b) => { + SExp::Cons(l, a, b) => { let a_filtered = filter_capture_args(a.clone(), name_map); let b_filtered = filter_capture_args(b.clone(), name_map); if !truthy(a_filtered.clone()) && !truthy(b_filtered.clone()) { return Rc::new(SExp::Nil(l.clone())); } - Rc::new(SExp::Cons(l.clone(),a_filtered,b_filtered)) + Rc::new(SExp::Cons(l.clone(), a_filtered, b_filtered)) } - SExp::Atom(l,n) => { + SExp::Atom(l, n) => { if name_map.contains_key(n) { Rc::new(SExp::Nil(l.clone())) } else { args } } - _ => Rc::new(SExp::Nil(args.loc())) + _ => Rc::new(SExp::Nil(args.loc())), } } @@ -1226,13 +1226,13 @@ impl<'info> Evaluator { create_argument_captures( &mut arg_captures, &deconsed_args, - ldata.capture_args.clone() + ldata.capture_args.clone(), )?; // Filter out elements that are not interpretable yet. let mut interpretable_captures = HashMap::new(); - for (n,v) in arg_captures.iter() { - if let Ok(_) = dequote(v.loc(), v.clone()) { + for (n, v) in arg_captures.iter() { + if dequote(v.loc(), v.clone()).is_ok() { // This capture has already been made into a literal. // We will substitute it in the lambda body and remove it // from the capture set. @@ -1243,7 +1243,7 @@ impl<'info> Evaluator { let combined_args = Rc::new(SExp::Cons( ldata.loc.clone(), ldata.capture_args.clone(), - ldata.args.clone() + ldata.args.clone(), )); // Eliminate the captures via beta substituion. @@ -1253,13 +1253,11 @@ impl<'info> Evaluator { combined_args.clone(), &interpretable_captures, ldata.body.clone(), - only_inline + only_inline, )?; - let new_capture_args = filter_capture_args( - ldata.capture_args.clone(), - &interpretable_captures, - ); + let new_capture_args = + filter_capture_args(ldata.capture_args.clone(), &interpretable_captures); Ok(Rc::new(BodyForm::Lambda(Box::new(LambdaData { args: ldata.args.clone(), capture_args: new_capture_args, diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 808acfb75..7ed47e159 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -378,7 +378,7 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { BodyForm::Mod(l, program) => Ok(BodyForm::Mod(l.clone(), program.clone())), BodyForm::Lambda(ldata) => { let mut own_args = HashMap::new(); - for (n,v) in invent_new_names_sexp(ldata.args.clone()).iter() { + for (n, v) in invent_new_names_sexp(ldata.args.clone()).iter() { own_args.insert(n.clone(), v.clone()); } let new_args = rename_in_cons(&own_args, ldata.args.clone(), false); @@ -389,7 +389,7 @@ fn rename_args_bodyform(b: &BodyForm) -> Result { body: Rc::new(renamed_with_own_args), ..*ldata.clone() }))) - }, + } } } diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index 133a52e08..1922b23d5 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -68,12 +68,19 @@ pub fn run_string(content: &String, args: &String) -> Result, CompileEr // order them and use a locally predictable renaming scheme to give them a final // test checkable value. pub fn squash_name_differences(in_sexp: Rc) -> Result, String> { - let found_names_set: BTreeSet<_> = collect_used_names_sexp(in_sexp.clone()).into_iter().filter(|n| n.contains(&b'$')).collect(); + let found_names_set: BTreeSet<_> = collect_used_names_sexp(in_sexp.clone()) + .into_iter() + .filter(|n| n.contains(&b'$')) + .collect(); let mut found_names_progression = b'A'; let mut replacement_map = HashMap::new(); for found_name in found_names_set.iter() { if let Some(located_dollar_part) = found_name.iter().position(|x| *x == b'$') { - let mut new_name: Vec = found_name.iter().take(located_dollar_part + 2).copied().collect(); + let mut new_name: Vec = found_name + .iter() + .take(located_dollar_part + 2) + .copied() + .collect(); new_name.push(found_names_progression); found_names_progression += 1; replacement_map.insert(found_name.clone(), new_name); @@ -82,7 +89,9 @@ pub fn squash_name_differences(in_sexp: Rc) -> Result, String> { } } if replacement_map.len() != found_names_set.len() { - return Err(format!("mismatched lengths {replacement_map:?} vs {found_names_set:?}")); + return Err(format!( + "mismatched lengths {replacement_map:?} vs {found_names_set:?}" + )); } Ok(rename_in_cons(&replacement_map, in_sexp, false)) } @@ -2231,7 +2240,11 @@ fn test_rename_in_compileform_simple() { let parsed = parse_sexp(Srcloc::start("*test*"), prog.bytes()).expect("should parse"); let opts: Rc = Rc::new(DefaultCompilerOpts::new(&"*test*".to_string())); let compiled = frontend(opts, &parsed).expect("should compile"); - let helper_f: Vec<_> = compiled.helpers.iter().filter(|f| f.name() == b"F").collect(); + let helper_f: Vec<_> = compiled + .helpers + .iter() + .filter(|f| f.name() == b"F") + .collect(); let renamed_helperform = squash_name_differences(helper_f[0].to_sexp()).expect("should rename"); assert_eq!(renamed_helperform.to_string(), desired_outcome); } diff --git a/src/tests/compiler/evaluate.rs b/src/tests/compiler/evaluate.rs index f2df4a391..df42a5fa0 100644 --- a/src/tests/compiler/evaluate.rs +++ b/src/tests/compiler/evaluate.rs @@ -38,7 +38,8 @@ fn shrink_expr_from_string(s: String) -> Result { ); })?; - let result_sexp = squash_name_differences(result.to_sexp()).map_err(|e| CompileErr(loc.clone(), e))?; + let result_sexp = + squash_name_differences(result.to_sexp()).map_err(|e| CompileErr(loc.clone(), e))?; Ok(result_sexp.to_string()) } @@ -125,7 +126,6 @@ fn test_simple_fe_opt_compile_1() { #[test] fn test_lambda_eval_1() { - assert_eq!( shrink_expr_from_string("(lambda (X) (+ X 1))".to_string()).unwrap(), "(lambda (X_$_A) (+ X_$_A 1))".to_string() From ec0104b559ae4925af9c03d72ac6e8680ae1811d Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 7 Sep 2023 11:07:19 -0700 Subject: [PATCH 138/196] Add some documentation --- wasm/README.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/wasm/README.md b/wasm/README.md index a8af1335d..338f7941d 100644 --- a/wasm/README.md +++ b/wasm/README.md @@ -30,3 +30,86 @@ Prerequisite: # Make sure you're at /wasm node ./tests/index.js ``` + +Program +=== + +Program is exported by ```clvm_tools_rs``` and contains a ```to``` function +among a few others. Its use is very like Program.to in the python code and +similar to chiaminejp's ```clvm_tools``` library. It produces a value that +can be used together with other such values, can be curried (and uncurried) +converted to the hex representation and run. + +```Program.to``` + +Converts javascript values to SExp objects which can be used together and run +as CLVM programs or used as program arguments. This conversion follows simple +conventions that were established in ```clvm_tools```. + +- There's a tuple object returned by the ```t``` function (2 arguments) which +produces a cons. + +- javascript arrays are treated as linear proper lists. Each element appears +as the first of a cons with the rest of the converted list as its tail. The +list is terminated by a nil. + +- an object which has a serialize method treats the result of ```o.serialize()``` +as an array-like object which specifies the byte values of the object's atom +representation. This covers bls primitives such as G1Element and G2Element. + +- javascript numbers, bignums, strings and bools are treated as atoms. + +- javascript objects which contain an array-like ```pair``` member are treated +the same as tuple objects above. + +```Program.from_hex``` + +Converts a string of pairs of hex digits into the CLVM deserialized form of the +object. + +```Program.null``` + +Returns a null object. + +The returned objects have these methods: + +```SExp.toString()``` + +Convert the object to its hex representation. + +```SExp.as_pair()``` + +If it is a cons, return a tuple-compatible object containing a ```pair``` array +with 2 elements, otherwise null. + +```SExp.listp()``` + +Return true if the object is a cons. + +```SExp.nullp()``` + +Return true if the object is falsey. + +```SExp.as_int()``` + +Returns a javascript number that fits within the 32-bit integers representing the object's atom value, or throw. + +```SExp.as_bigint()``` + +Returns a javascript big number representing the value of the given atom or throw. + +```SExp.first()``` + +If the object is a cons, return its first or left component, or throw if not. + +```SExp.rest()``` + +If the object is a cons, return its rest or right component, or throw if not. + +```SExp.cons(other)``` + +Creates an SExp which is a cons of this sexp and other. + +```SExp.run(env)``` + +Runs the indicated SExp as a program with the given environment. From 73fe7d672346f13916b8906c8304beddbcd19a3a Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 7 Sep 2023 14:10:43 -0700 Subject: [PATCH 139/196] Add more docs --- wasm/README.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/wasm/README.md b/wasm/README.md index 338f7941d..dc8933ce0 100644 --- a/wasm/README.md +++ b/wasm/README.md @@ -40,7 +40,7 @@ similar to chiaminejp's ```clvm_tools``` library. It produces a value that can be used together with other such values, can be curried (and uncurried) converted to the hex representation and run. -```Program.to``` +```Program.to(javascript_value)``` Converts javascript values to SExp objects which can be used together and run as CLVM programs or used as program arguments. This conversion follows simple @@ -62,17 +62,20 @@ representation. This covers bls primitives such as G1Element and G2Element. - javascript objects which contain an array-like ```pair``` member are treated the same as tuple objects above. -```Program.from_hex``` +```Program.from_hex(hex_str)``` Converts a string of pairs of hex digits into the CLVM deserialized form of the object. -```Program.null``` +```Program.null()``` Returns a null object. The returned objects have these methods: +SExp methods +=== + ```SExp.toString()``` Convert the object to its hex representation. @@ -113,3 +116,24 @@ Creates an SExp which is a cons of this sexp and other. ```SExp.run(env)``` Runs the indicated SExp as a program with the given environment. + +```SExp.as_bin()``` + +Serialize the object into an array of byte values. + +```SExp.list_len()``` + +Give the number of conses one needs to traverse until reaching a non-cons rest. +For a proper list, this gives the list's length. + +```SExp.as_javascript()``` + +Return a javascript value that allows the given SExp to be inspected via +javascript. + +```SExp.curry(a, b, c ...)``` + +Given a number of positional arguments, build a curried application that provides +values for the left arguments of some runnable CLVM code, giving code that can +be correctly called with fewer arguments. This is common for providing values to +the upper case parameters of chialisp programs, such as coin puzzles. From f01f9f241516bf51e1b43afe78299c92ff9a6e2c Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 8 Sep 2023 09:47:23 -0700 Subject: [PATCH 140/196] Fix up clippy warnings in objects.rs --- wasm/src/api.rs | 54 +++++++++------------ wasm/src/objects.rs | 114 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 127 insertions(+), 41 deletions(-) diff --git a/wasm/src/api.rs b/wasm/src/api.rs index fe319cad5..333057018 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -97,11 +97,8 @@ where runcell.replace_with(|coll| { let mut work_collection = HashMap::new(); swap(coll, &mut work_collection); - match work_collection.get_mut(&this_id) { - Some(r_ref) => { - result = f(r_ref); - } - _ => {} + if let Some(r_ref) = work_collection.get_mut(&this_id) { + result = f(r_ref); } work_collection }); @@ -115,16 +112,16 @@ pub fn create_clvm_runner_err(error: String) -> JsValue { 0, js_pair(JsValue::from_str("error"), JsValue::from_str(&error)), ); - return object_to_value(&js_sys::Object::from_entries(&array).unwrap()); + object_to_value(&js_sys::Object::from_entries(&array).unwrap()) } fn create_clvm_runner_run_failure(err: &RunFailure) -> JsValue { match err { RunFailure::RunErr(l, e) => { - return create_clvm_runner_err(format!("{}: Error {}", l.to_string(), e)); + create_clvm_runner_err(format!("{}: Error {}", l, e)) } RunFailure::RunExn(l, e) => { - return create_clvm_runner_err(format!("{}: Exn {}", l.to_string(), e.to_string())) + create_clvm_runner_err(format!("{}: Exn {}", l, e)) } } } @@ -132,7 +129,7 @@ fn create_clvm_runner_run_failure(err: &RunFailure) -> JsValue { fn create_clvm_compile_failure(err: &CompileErr) -> JsValue { match err { CompileErr(l, e) => { - return create_clvm_runner_err(format!("{}: Error {}", l.to_string(), e)); + create_clvm_runner_err(format!("{}: Error {}", l, e)) } } } @@ -159,7 +156,7 @@ impl CldbSingleBespokeOverride for JsBespokeOverride { }) .and_then(|v| { sexp_from_js_object(env.loc(), &v) - .map(|s| Ok(s)) + .map(Ok) .unwrap_or_else(|| { Err(RunFailure::RunErr( env.loc(), @@ -183,8 +180,8 @@ pub fn create_clvm_runner( ) -> JsValue { let mut allocator = Allocator::new(); let runner = Rc::new(DefaultProgramRunner::new()); - let args_srcloc = Srcloc::start(&"*args*".to_string()); - let prog_srcloc = Srcloc::start(&"*program*".to_string()); + let args_srcloc = Srcloc::start("*args*"); + let prog_srcloc = Srcloc::start("*program*"); let mut prim_map = HashMap::new(); let mut override_funs: HashMap> = HashMap::new(); @@ -208,14 +205,11 @@ pub fn create_clvm_runner( } }; - for ent in js_sys::Object::keys(&overrides).values() { + for ent in js_sys::Object::keys(overrides).values() { let key = ent.unwrap().as_string().unwrap(); - let val = get_property(&overrides, &key).unwrap(); - match val.dyn_ref::() { - Some(f) => { - override_funs.insert(key, Box::new(JsBespokeOverride { fun: f.clone() })); - } - _ => {} + let val = get_property(overrides, &key).unwrap(); + if let Some(f) = val.dyn_ref::() { + override_funs.insert(key, Box::new(JsBespokeOverride { fun: f.clone() })); } } @@ -247,7 +241,7 @@ pub fn create_clvm_runner( let this_id = get_next_id(); insert_runner(this_id, JsRunStep { allocator, cldbrun }); - return JsValue::from(this_id); + JsValue::from(this_id) } #[wasm_bindgen] @@ -255,7 +249,7 @@ pub fn final_value(runner: i32) -> JsValue { with_runner(runner, |r| { r.cldbrun.final_result().map(|v| js_object_from_sexp(v).unwrap_or_else(|e| e)) }) - .unwrap_or_else(|| JsValue::null()) + .unwrap_or_else(JsValue::null) } #[wasm_bindgen] @@ -274,7 +268,7 @@ pub fn run_step(runner: i32) -> JsValue { r.cldbrun.step(&mut r.allocator) }) .map(|result_hash| btreemap_to_object(result_hash.iter())) - .unwrap_or_else(|| JsValue::null()) + .unwrap_or_else(JsValue::null) } fn make_compile_output(result_stream: &Stream, symbol_table: &HashMap) -> JsValue { @@ -285,10 +279,8 @@ fn make_compile_output(result_stream: &Stream, symbol_table: &HashMap JsValue { let mut allocator = Allocator::new(); - let loc = Srcloc::start(&"*js*".to_string()); + let loc = Srcloc::start("*js*"); let symbol_table = match read_string_to_string_map(symbol_table_js) { Ok(s) => s, Err(e) => { @@ -417,7 +409,7 @@ pub fn compose_run_function( #[wasm_bindgen] pub fn create_repl() -> i32 { let allocator = Allocator::new(); - let opts = Rc::new(DefaultCompilerOpts::new(&"*repl*".to_string())); + let opts = Rc::new(DefaultCompilerOpts::new("*repl*")); let runner = Rc::new(DefaultProgramRunner::new()); let repl = Repl::new(opts, runner.clone()); let new_id = get_next_id(); @@ -470,7 +462,7 @@ pub fn repl_run_string(repl_id: i32, input: String) -> JsValue { r.process_line(a, input) } else { Err(CompileErr( - Srcloc::start(&"*repl*".to_string()), + Srcloc::start("*repl*"), "no such repl".to_string(), )) } @@ -483,12 +475,12 @@ pub fn repl_run_string(repl_id: i32, input: String) -> JsValue { e.1 ))) }) - .unwrap_or_else(|| JsValue::null()) + .unwrap_or_else(JsValue::null) } #[wasm_bindgen] pub fn sexp_to_string(v: &JsValue) -> JsValue { - let loc = Srcloc::start(&"*val*".to_string()); + let loc = Srcloc::start("*val*"); sexp_from_js_object(loc, v) .map(|s| JsValue::from_str(&s.to_string())) diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 3bd701f3d..3e13b3421 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -129,7 +129,7 @@ impl ObjectCache { } } -static PROGRAM_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ +static PROGRAM_FUNCTIONS: &[FunctionWrapperDesc] = &[ FunctionWrapperDesc { export_name: "toString", member_name: "to_string_internal", @@ -209,10 +209,20 @@ static PROGRAM_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ export_name: "sha256tree", member_name: "sha256tree_internal", varargs: false, - } + }, + FunctionWrapperDesc { + export_name: "uncurry_error", + member_name: "uncurry_error_internal", + varargs: false, + }, + FunctionWrapperDesc { + export_name: "uncurry", + member_name: "uncurry_internal", + varargs: false, + }, ]; -static TUPLE_FUNCTIONS: &'static [FunctionWrapperDesc] = &[ +static TUPLE_FUNCTIONS: &[FunctionWrapperDesc] = &[ FunctionWrapperDesc { export_name: "to_program", member_name: "tuple_to_program_internal", @@ -365,6 +375,40 @@ pub fn finish_new_object(id: i32, encoded_hex: &str) -> Result Ok(new_object.into()) } +// Return a vector of arguments if the given SExp is the expected operator +// and has the required number of arguments. +fn match_op(opcode: u8, expected_args: usize, opname: &str, program: Rc) -> Result>, JsValue> { + let plist = + if let Some(plist) = program.proper_list() { + plist + } else { + // Not a list so can't be an apply. + return Err(JsValue::from_str(&format!("program wasn't a list representing an {opname} op: {program}"))); + }; + + // Not the right length + if plist.len() != expected_args + 1 { + return Err(JsValue::from_str(&format!("program list wasn't a list of {} representing an {opname} op: {program}", expected_args + 1))); + } + + // Not an apply + if plist[0] != SExp::Atom(plist[0].loc(), vec![opcode]) { + return Err(JsValue::from_str("program isn't an {opname} op: {program}")); + } + + Ok(plist.into_iter().skip(1).map(Rc::new).collect()) +} + +fn cache_and_accumulate_arg(array: &Array, prog: Rc) -> Result<(), JsValue> { + let arg_id = get_next_id(); + let new_cached_arg = create_cached_sexp(arg_id, prog)?; + let arg_js = finish_new_object(arg_id, &new_cached_arg)?; + + array.push(&arg_js); + + Ok(()) +} + #[wasm_bindgen] impl Program { #[wasm_bindgen] @@ -595,13 +639,9 @@ impl Program { let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; let mut val_ref = cached.modern.clone(); let mut count: i32 = 0; - loop { - if let SExp::Cons(_, _, b) = val_ref.borrow() { - val_ref = b.clone(); - count += 1; - } else { - break; - } + while let SExp::Cons(_, _, b) = val_ref.borrow() { + val_ref = b.clone(); + count += 1; } Ok(count) } @@ -674,4 +714,58 @@ impl Program { let new_cached = create_cached_sexp(new_id, result)?; finish_new_object(new_id, &new_cached) } + + #[wasm_bindgen] + pub fn uncurry_error_internal(obj: &JsValue) -> Result { + let program_val = Program::to(obj)?; + let cacheval = js_cache_value_from_js(&program_val)?; + let program = find_cached_sexp(cacheval.entry, &cacheval.content)?; + + let apply_args = match_op(2, 2, "apply", program.modern.clone())?; + // Not used in code, but detects a quoted program. + let quoted_prog = match_op(1, 1, "quote", apply_args[0].clone())?; + + let retrieved_args = Array::new(); + let mut cons_expr = match_op(4, 2, "cons", apply_args[1].clone())?; + cache_and_accumulate_arg(&retrieved_args, cons_expr[0].clone())?; + let mut next_cons = cons_expr[1].clone(); + while matches!(next_cons.borrow(), SExp::Cons(_, _, _)) { + cons_expr = match_op(4, 2, "cons", next_cons)?; + + // Convert to the external js form and insert into cache so we can + // forego conversion if still cached. + cache_and_accumulate_arg(&retrieved_args, cons_expr[0].clone())?; + + // Move on to the tail that's being built. + next_cons = cons_expr[1].clone(); + } + + // Verify that we're at a 1 env ref. + let borrowed_next: &SExp = next_cons.borrow(); + if borrowed_next != &SExp::Atom(next_cons.loc(), vec![1]) { + return Err(JsValue::from_str("curry didn't end with 1 env ref")); + } + + // Make a cache slot for the program. + let mod_id = get_next_id(); + let new_cached_mod = create_cached_sexp(mod_id, quoted_prog[0].clone())?; + let mod_js = finish_new_object(mod_id, &new_cached_mod)?; + + let res = Array::new(); + res.push(&mod_js); + res.push(&retrieved_args); + Ok(res.into()) + } + + #[wasm_bindgen] + pub fn uncurry_internal(obj: &JsValue) -> JsValue { + if let Ok(res) = Program::uncurry_error_internal(obj) { + res + } else { + let res = Array::new(); + res.push(obj); + res.push(&JsValue::null()); + res.into() + } + } } From 4bb3d77e49e3d22adab17bfdc0a6c5bc6c914091 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 8 Sep 2023 09:59:40 -0700 Subject: [PATCH 141/196] Add a bit more docs --- wasm/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wasm/README.md b/wasm/README.md index dc8933ce0..d73c2b4c6 100644 --- a/wasm/README.md +++ b/wasm/README.md @@ -137,3 +137,11 @@ Given a number of positional arguments, build a curried application that provide values for the left arguments of some runnable CLVM code, giving code that can be correctly called with fewer arguments. This is common for providing values to the upper case parameters of chialisp programs, such as coin puzzles. + +```SExp.uncurry(program) -> [inner_program, [args...]]``` +```SExp.uncurry_error(program)``` + +Uncurry returns an array with the inner program and the retrievable arguments +separated out, or the original program and null. uncurry_error throws instead +of returning a value if the object wasn't a curried program. + From abd854ebe15e7771dceb2bc2d94870d26fe74694 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 11 Sep 2023 12:12:05 -0700 Subject: [PATCH 142/196] Start bringing in compile context --- src/compiler/mod.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index af2c6ff15..a1b4adf6b 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -20,7 +20,7 @@ pub mod evaluate; pub mod frontend; pub mod gensym; mod inline; -mod optimize; +pub mod optimize; pub mod preprocessor; pub mod prims; pub mod rename; @@ -30,3 +30,92 @@ pub mod sexp; pub mod srcloc; pub mod stackvisit; pub mod usecheck; + +use clvmr::allocator::Allocator; +use std::collections::HashMap; +use std::mem::swap; +use std::rc::Rc; + +use crate::classic::clvm_tools::stages::stage_0::TRunProgram; +use crate::compiler::comptypes::{ + BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, +}; +use crate::compiler::sexp::SExp; + +/// An object which represents the standard set of mutable items passed down the +/// stack when compiling chialisp. +pub struct BasicCompileContext { + pub allocator: Allocator, + pub runner: Rc, + pub symbols: HashMap, +} + +impl BasicCompileContext { + fn allocator(&mut self) -> &mut Allocator { + &mut self.allocator + } + fn runner(&self) -> Rc { + self.runner.clone() + } + fn symbols(&mut self) -> &mut HashMap { + &mut self.symbols + } + + pub fn new( + allocator: Allocator, + runner: Rc, + symbols: HashMap, + ) -> Self { + BasicCompileContext { + allocator, + runner, + symbols, + } + } +} + +pub struct CompileContextWrapper<'a> { + pub allocator: &'a mut Allocator, + pub symbols: &'a mut HashMap, + pub context: BasicCompileContext, +} + +impl<'a> CompileContextWrapper<'a> { + pub fn new( + allocator: &'a mut Allocator, + runner: Rc, + symbols: &'a mut HashMap, + ) -> Self { + let bcc = BasicCompileContext { + allocator: Allocator::new(), + runner, + symbols: HashMap::new(), + }; + let mut wrapper = CompileContextWrapper { + allocator, + symbols, + context: bcc, + }; + wrapper.switch(); + wrapper + } + + fn switch(&mut self) { + swap(self.allocator, &mut self.context.allocator); + swap(self.symbols, &mut self.context.symbols); + } +} + +impl<'a> Drop for CompileContextWrapper<'a> { + fn drop(&mut self) { + self.switch(); + } +} + +/// Describes the unique inputs and outputs available at the start of code +/// generation. +#[derive(Debug, Clone)] +pub struct StartOfCodegenOptimization { + program: CompileForm, + code_generator: PrimaryCodegen, +} From cf96119e92c790bb622aa15e5ff9b5e4af39669c Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 11 Sep 2023 12:53:39 -0700 Subject: [PATCH 143/196] Add compile context, pure refactor --- src/classic/clvm_tools/clvmc.rs | 35 +++++- src/compiler/codegen.rs | 215 +++++++++++++------------------- src/compiler/compiler.rs | 24 ++-- src/compiler/evaluate.rs | 12 +- src/compiler/inline.rs | 9 +- src/compiler/mod.rs | 12 -- 6 files changed, 141 insertions(+), 166 deletions(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index 4a1beb076..d51162373 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -38,8 +38,9 @@ pub fn write_sym_output( .map(|_| ()) } -pub fn compile_clvm_text( +pub fn compile_clvm_text_maybe_opt( allocator: &mut Allocator, + do_optimize: bool, opts: Rc, symbol_table: &mut HashMap, text: &str, @@ -52,12 +53,19 @@ pub fn compile_clvm_text( let dialect = detect_modern(allocator, assembled_sexp); // Now the stepping is optional (None for classic) but we may communicate // other information in dialect as well. - if let Some(dialect) = dialect.stepping { + if let Some(stepping) = dialect.stepping { let runner = Rc::new(DefaultProgramRunner::new()); - let opts = opts.set_optimize(true).set_frontend_opt(dialect > 21); + let opts = opts + .set_dialect(dialect) + .set_optimize(do_optimize || stepping > 22) + .set_frontend_opt(stepping == 22); let unopt_res = compile_file(allocator, runner.clone(), opts, text, symbol_table); - let res = unopt_res.and_then(|x| run_optimizer(allocator, runner, Rc::new(x))); + let res = if do_optimize { + unopt_res.and_then(|x| run_optimizer(allocator, runner, Rc::new(x))) + } else { + unopt_res.map(Rc::new) + }; res.and_then(|x| { convert_to_clvm_rs(allocator, x).map_err(|r| match r { @@ -79,6 +87,25 @@ pub fn compile_clvm_text( } } +pub fn compile_clvm_text( + allocator: &mut Allocator, + opts: Rc, + symbol_table: &mut HashMap, + text: &str, + input_path: &str, + classic_with_opts: bool, +) -> Result { + compile_clvm_text_maybe_opt( + allocator, + true, + opts, + symbol_table, + text, + input_path, + classic_with_opts, + ) +} + pub fn compile_clvm_inner( allocator: &mut Allocator, opts: Rc, diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index fdf651b3e..f224c6852 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -6,9 +6,6 @@ use std::rc::Rc; use num_bigint::ToBigInt; -use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use clvm_rs::allocator::Allocator; - use crate::classic::clvm::__type_compatibility__::bi_one; use crate::compiler::clvm::run; @@ -29,6 +26,7 @@ use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; +use crate::compiler::{BasicCompileContext, CompileContextWrapper}; use crate::util::{toposort, u8_from_number, TopoSortItem}; const MACRO_TIME_LIMIT: usize = 1000000; @@ -256,8 +254,7 @@ pub fn get_callable( } pub fn process_macro_call( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, l: Srcloc, @@ -269,9 +266,10 @@ pub fn process_macro_call( let args_to_macro = list_to_cons(l.clone(), &converted_args); build_swap_table_mut(&mut swap_table, &args_to_macro); + let runner = context.runner(); run( - allocator, - runner.clone(), + context.allocator(), + runner, opts.prim_map(), code, Rc::new(args_to_macro), @@ -285,12 +283,11 @@ pub fn process_macro_call( let relabeled_expr = relabel(&swap_table, &v); compile_bodyform(opts.clone(), Rc::new(relabeled_expr)) }) - .and_then(|body| generate_expr_code(allocator, runner, opts, compiler, Rc::new(body))) + .and_then(|body| generate_expr_code(context, opts, compiler, Rc::new(body))) } fn generate_args_code( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, call: &CallSpec, @@ -303,7 +300,7 @@ fn generate_args_code( // Ensure we start with either the specified tail or nil. let mut compiled_args: Rc = if let Some(t) = call.tail.as_ref() { - generate_expr_code(allocator, runner.clone(), opts.clone(), compiler, t.clone())?.1 + generate_expr_code(context, opts.clone(), compiler, t.clone())?.1 } else { Rc::new(SExp::Nil(call.loc.clone())) }; @@ -311,14 +308,7 @@ fn generate_args_code( // Now that we have the tail, generate the code for each argument in reverse // order to cons on. for hd in call.args.iter().rev() { - let generated = generate_expr_code( - allocator, - runner.clone(), - opts.clone(), - compiler, - hd.clone(), - )? - .1; + let generated = generate_expr_code(context, opts.clone(), compiler, hd.clone())?.1; // This function is now reused for purposes that make a simple list of the // converted arguments, or generate valid code with primitive conses. @@ -372,8 +362,7 @@ pub fn get_call_name(l: Srcloc, body: BodyForm) -> Result, CompileErr> } fn compile_call( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, call: &RawCallSpec, @@ -401,19 +390,12 @@ fn compile_call( Rc::new(SExp::Atom(al.clone(), an.to_vec())), ) .and_then(|calltype| match calltype { - Callable::CallMacro(l, code) => process_macro_call( - allocator, - runner, - opts.clone(), - compiler, - l, - tl, - Rc::new(code), - ), + Callable::CallMacro(l, code) => { + process_macro_call(context, opts.clone(), compiler, l, tl, Rc::new(code)) + } Callable::CallInline(l, inline) => replace_in_inline( - allocator, - runner.clone(), + context, opts.clone(), compiler, l.clone(), @@ -424,8 +406,7 @@ fn compile_call( ), Callable::CallDefun(l, lookup) => generate_args_code( - allocator, - runner, + context, opts.clone(), compiler, // A callspec is a way to collect some info about a call, mainly @@ -444,8 +425,7 @@ fn compile_call( }), Callable::CallPrim(l, p) => generate_args_code( - allocator, - runner.clone(), + context, opts, compiler, &CallSpec { @@ -502,9 +482,10 @@ fn compile_call( ); let mut unused_symbol_table = HashMap::new(); + let runner = context.runner(); updated_opts .compile_program( - allocator, + context.allocator(), runner, Rc::new(use_body), &mut unused_symbol_table, @@ -532,9 +513,30 @@ fn compile_call( } } +pub fn do_mod_codegen( + context: &mut BasicCompileContext, + opts: Rc, + program: &CompileForm, +) -> Result { + // A mod form yields the compiled code. + let without_env = opts.set_start_env(None).set_in_defun(false); + let mut throwaway_symbols = HashMap::new(); + let runner = context.runner(); + let mut context_wrapper = + CompileContextWrapper::new(context.allocator(), runner.clone(), &mut throwaway_symbols); + let code = codegen(&mut context_wrapper.context, without_env, program)?; + Ok(CompiledCode( + program.loc.clone(), + Rc::new(SExp::Cons( + program.loc.clone(), + Rc::new(SExp::Atom(program.loc.clone(), vec![1])), + Rc::new(code), + )), + )) +} + pub fn generate_expr_code( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, expr: Rc, @@ -543,7 +545,7 @@ pub fn generate_expr_code( BodyForm::Let(LetFormKind::Parallel, letdata) => { /* Depends on a defun having been desugared from this let and the let expressing rewritten. */ - generate_expr_code(allocator, runner, opts, compiler, letdata.body.clone()) + generate_expr_code(context, opts, compiler, letdata.body.clone()) } BodyForm::Quoted(q) => { let l = q.loc(); @@ -568,8 +570,7 @@ pub fn generate_expr_code( // macros, as it's possible that a macro returned // something that's canonically a name in number form. generate_expr_code( - allocator, - runner, + context, opts, compiler, Rc::new(BodyForm::Quoted(SExp::Atom(l.clone(), atom.clone()))), @@ -582,8 +583,7 @@ pub fn generate_expr_code( // accomodate bare numbers coming back in place of identifiers. // I'm considering ways to make this better. SExp::Integer(l, i) => generate_expr_code( - allocator, - runner, + context, opts, compiler, Rc::new(BodyForm::Value(SExp::Atom( @@ -605,8 +605,7 @@ pub fn generate_expr_code( )) } else { compile_call( - allocator, - runner, + context, opts, compiler, // This is a partial callspec. @@ -619,18 +618,7 @@ pub fn generate_expr_code( ) } } - BodyForm::Mod(_, program) => { - // A mod form yields the compiled code. - let code = codegen(allocator, runner, opts, program, &mut HashMap::new())?; - Ok(CompiledCode( - program.loc.clone(), - Rc::new(SExp::Cons( - program.loc.clone(), - Rc::new(SExp::Atom(program.loc.clone(), vec![1])), - Rc::new(code), - )), - )) - } + BodyForm::Mod(_, program) => do_mod_codegen(context, opts, program), _ => Err(CompileErr( expr.loc(), format!("don't know how to compile {}", expr.to_sexp()), @@ -663,8 +651,7 @@ fn fail_if_present( } fn codegen_( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, h: &HelperForm, @@ -692,12 +679,13 @@ fn codegen_( defun.args.clone(), ))); + let runner = context.runner(); let opt = if opts.optimize() { // Run optimizer on frontend style forms. optimize_expr( - allocator, + context.allocator(), opts.clone(), - runner.clone(), + runner, compiler, defun.body.clone(), ) @@ -722,16 +710,17 @@ fn codegen_( ); let mut unused_symbol_table = HashMap::new(); + let runner = context.runner(); updated_opts .compile_program( - allocator, + context.allocator(), runner.clone(), Rc::new(tocompile), &mut unused_symbol_table, ) .and_then(|code| { if opts.optimize() { - run_optimizer(allocator, runner, Rc::new(code)) + run_optimizer(context.allocator(), runner, Rc::new(code)) } else { Ok(Rc::new(code)) } @@ -1165,8 +1154,7 @@ pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Result, + context: &mut BasicCompileContext, opts: Rc, program: CompileForm, ) -> Result { @@ -1195,15 +1183,16 @@ fn start_codegen( )), ); let updated_opts = opts.set_code_generator(code_generator.clone()); + let runner = context.runner(); let code = updated_opts.compile_program( - allocator, + context.allocator(), runner.clone(), Rc::new(expand_program), &mut HashMap::new(), )?; run( - allocator, - runner.clone(), + context.allocator(), + runner, opts.prim_map(), Rc::new(code), Rc::new(SExp::Nil(defc.loc.clone())), @@ -1227,9 +1216,9 @@ fn start_codegen( } ConstantKind::Complex => { let evaluator = - Evaluator::new(opts.clone(), runner.clone(), program.helpers.clone()); + Evaluator::new(opts.clone(), context.runner(), program.helpers.clone()); let constant_result = evaluator.shrink_bodyform( - allocator, + context.allocator(), Rc::new(SExp::Nil(defc.loc.clone())), &HashMap::new(), defc.body.clone(), @@ -1270,16 +1259,17 @@ fn start_codegen( .set_stdenv(false) .set_frontend_opt(false); + let runner = context.runner(); updated_opts .compile_program( - allocator, + context.allocator(), runner.clone(), macro_program, &mut HashMap::new(), ) .and_then(|code| { if opts.optimize() { - run_optimizer(allocator, runner.clone(), Rc::new(code)) + run_optimizer(context.allocator(), runner, Rc::new(code)) } else { Ok(Rc::new(code)) } @@ -1314,16 +1304,16 @@ fn start_codegen( } fn final_codegen( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, ) -> Result { + let runner = context.runner(); let opt_final_expr = if opts.optimize() { optimize_expr( - allocator, + context.allocator(), opts.clone(), - runner.clone(), + runner, compiler, compiler.final_expr.clone(), ) @@ -1333,7 +1323,7 @@ fn final_codegen( compiler.final_expr.clone() }; - generate_expr_code(allocator, runner, opts, compiler, opt_final_expr).map(|code| { + generate_expr_code(context, opts, compiler, opt_final_expr).map(|code| { let mut final_comp = compiler.clone(); final_comp.final_code = Some(CompiledCode(code.0, code.1)); final_comp @@ -1341,8 +1331,7 @@ fn final_codegen( } fn finalize_env_( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, c: &PrimaryCodegen, _l: Srcloc, @@ -1357,8 +1346,7 @@ fn finalize_env_( Some(res) => { let (arg_list, arg_tail) = synthesize_args(res.args.clone()); replace_in_inline( - allocator, - runner.clone(), + context, opts.clone(), c, l.clone(), @@ -1388,45 +1376,23 @@ fn finalize_env_( } } - SExp::Cons(l, h, r) => finalize_env_( - allocator, - runner.clone(), - opts.clone(), - c, - l.clone(), - h.clone(), - ) - .and_then(|h| { - finalize_env_( - allocator, - runner.clone(), - opts.clone(), - c, - l.clone(), - r.clone(), - ) - .map(|r| Rc::new(SExp::Cons(l.clone(), h.clone(), r))) - }), + SExp::Cons(l, h, r) => finalize_env_(context, opts.clone(), c, l.clone(), h.clone()) + .and_then(|h| { + finalize_env_(context, opts.clone(), c, l.clone(), r.clone()) + .map(|r| Rc::new(SExp::Cons(l.clone(), h.clone(), r))) + }), _ => Ok(env.clone()), } } fn finalize_env( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, c: &PrimaryCodegen, ) -> Result, CompileErr> { match c.env.borrow() { - SExp::Cons(l, h, _) => finalize_env_( - allocator, - runner.clone(), - opts.clone(), - c, - l.clone(), - h.clone(), - ), + SExp::Cons(l, h, _) => finalize_env_(context, opts.clone(), c, l.clone(), h.clone()), _ => Ok(c.env.clone()), } } @@ -1464,30 +1430,25 @@ fn dummy_functions(compiler: &PrimaryCodegen) -> Result, + context: &mut BasicCompileContext, opts: Rc, cmod: &CompileForm, - symbol_table: &mut HashMap, ) -> Result { - let mut code_generator = dummy_functions(&start_codegen( - allocator, - runner.clone(), - opts.clone(), - cmod.clone(), - )?)?; + let mut code_generator = dummy_functions(&start_codegen(context, opts.clone(), cmod.clone())?)?; let to_process = code_generator.to_process.clone(); for f in to_process { - code_generator = codegen_(allocator, runner.clone(), opts.clone(), &code_generator, &f)?; + code_generator = codegen_(context, opts.clone(), &code_generator, &f)?; } - *symbol_table = code_generator.function_symbols.clone(); - symbol_table.insert("source_file".to_string(), opts.filename()); + *context.symbols() = code_generator.function_symbols.clone(); + context + .symbols() + .insert("source_file".to_string(), opts.filename()); - final_codegen(allocator, runner.clone(), opts.clone(), &code_generator).and_then(|c| { - let final_env = finalize_env(allocator, runner.clone(), opts.clone(), &c)?; + final_codegen(context, opts.clone(), &code_generator).and_then(|c| { + let final_env = finalize_env(context, opts.clone(), &c)?; match c.final_code { None => Err(CompileErr( @@ -1496,7 +1457,9 @@ pub fn codegen( )), Some(code) => { // Capture symbols now that we have the final form of the produced code. - symbol_table.insert("__chia__main_arguments".to_string(), cmod.args.to_string()); + context + .symbols() + .insert("__chia__main_arguments".to_string(), cmod.args.to_string()); if opts.in_defun() { let final_code = primapply( diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 5a5863617..9fb0c7098 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -23,6 +23,7 @@ use crate::compiler::prims; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::{parse_sexp, SExp}; use crate::compiler::srcloc::Srcloc; +use crate::compiler::{BasicCompileContext, CompileContextWrapper}; use crate::util::Number; lazy_static! { @@ -92,11 +93,11 @@ pub fn create_prim_map() -> Rc, Rc>> { } fn fe_opt( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compileform: CompileForm, ) -> Result { + let runner = context.runner(); let evaluator = Evaluator::new(opts.clone(), runner.clone(), compileform.helpers.clone()); let mut optimized_helpers: Vec = Vec::new(); for h in compileform.helpers.iter() { @@ -105,7 +106,7 @@ fn fe_opt( let mut env = HashMap::new(); build_reflex_captures(&mut env, defun.args.clone()); let body_rc = evaluator.shrink_bodyform( - allocator, + context.allocator(), defun.args.clone(), &env, defun.body.clone(), @@ -134,7 +135,7 @@ fn fe_opt( let new_evaluator = Evaluator::new(opts.clone(), runner.clone(), optimized_helpers.clone()); let shrunk = new_evaluator.shrink_bodyform( - allocator, + context.allocator(), Rc::new(SExp::Nil(compileform.args.loc())), &HashMap::new(), compileform.exp.clone(), @@ -152,18 +153,16 @@ fn fe_opt( } pub fn compile_pre_forms( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, pre_forms: &[Rc], - symbol_table: &mut HashMap, ) -> Result { // Resolve includes, convert program source to lexemes let p0 = frontend(opts.clone(), pre_forms)?; let p1 = if opts.frontend_opt() { // Front end optimization - fe_opt(allocator, runner.clone(), opts.clone(), p0)? + fe_opt(context, opts.clone(), p0)? } else { p0 }; @@ -187,7 +186,7 @@ pub fn compile_pre_forms( }; // generate code from AST, optionally with optimization - codegen(allocator, runner, opts, &p2, symbol_table) + codegen(context, opts, &p2) } pub fn compile_file( @@ -198,8 +197,8 @@ pub fn compile_file( symbol_table: &mut HashMap, ) -> Result { let pre_forms = parse_sexp(Srcloc::start(&opts.filename()), content.bytes())?; - - compile_pre_forms(allocator, runner, opts, &pre_forms, symbol_table) + let mut context_wrapper = CompileContextWrapper::new(allocator, runner, symbol_table); + compile_pre_forms(&mut context_wrapper.context, opts, &pre_forms) } pub fn run_optimizer( @@ -352,7 +351,8 @@ impl CompilerOpts for DefaultCompilerOpts { symbol_table: &mut HashMap, ) -> Result { let me = Rc::new(self.clone()); - compile_pre_forms(allocator, runner, me, &[sexp], symbol_table) + let mut context_wrapper = CompileContextWrapper::new(allocator, runner, symbol_table); + compile_pre_forms(&mut context_wrapper.context, me, &[sexp]) } } diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index bf6af75c3..fc5fac818 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -21,6 +21,7 @@ use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; use crate::compiler::stackvisit::{HasDepthLimit, VisitedMarker}; +use crate::compiler::CompileContextWrapper; use crate::util::{number_from_u8, u8_from_number, Number}; const PRIM_RUN_LIMIT: usize = 1000000; @@ -1222,13 +1223,10 @@ impl<'info> Evaluator { } BodyForm::Mod(_, program) => { // A mod form yields the compiled code. - let code = codegen( - allocator, - self.runner.clone(), - self.opts.clone(), - program, - &mut HashMap::new(), - )?; + let mut symbols = HashMap::new(); + let mut context_wrapper = + CompileContextWrapper::new(allocator, self.runner.clone(), &mut symbols); + let code = codegen(&mut context_wrapper.context, self.opts.clone(), program)?; Ok(Rc::new(BodyForm::Quoted(code))) } } diff --git a/src/compiler/inline.rs b/src/compiler/inline.rs index 604014e2b..c60a6e511 100644 --- a/src/compiler/inline.rs +++ b/src/compiler/inline.rs @@ -3,8 +3,6 @@ use std::borrow::Borrow; use std::collections::HashSet; use std::rc::Rc; -use clvm_rs::allocator::Allocator; - use crate::classic::clvm::__type_compatibility__::bi_one; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; @@ -16,6 +14,7 @@ use crate::compiler::comptypes::{ }; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; +use crate::compiler::BasicCompileContext; use crate::util::Number; @@ -468,8 +467,7 @@ fn replace_inline_body( /// tail argument if one exists. If not, then they're discarded. #[allow(clippy::too_many_arguments)] pub fn replace_in_inline( - allocator: &mut Allocator, - runner: Rc, + context: &mut BasicCompileContext, opts: Rc, compiler: &PrimaryCodegen, loc: Srcloc, @@ -479,6 +477,7 @@ pub fn replace_in_inline( tail: Option>, ) -> Result { let mut visited = HashSet::new(); + let runner = context.runner(); visited.insert(inline.name.clone()); replace_inline_body( &mut visited, @@ -492,5 +491,5 @@ pub fn replace_in_inline( callsite, inline.body.clone(), ) - .and_then(|x| generate_expr_code(allocator, runner, opts, compiler, x)) + .and_then(|x| generate_expr_code(context, opts, compiler, x)) } diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index a1b4adf6b..63133533a 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -37,10 +37,6 @@ use std::mem::swap; use std::rc::Rc; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::comptypes::{ - BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, -}; -use crate::compiler::sexp::SExp; /// An object which represents the standard set of mutable items passed down the /// stack when compiling chialisp. @@ -111,11 +107,3 @@ impl<'a> Drop for CompileContextWrapper<'a> { self.switch(); } } - -/// Describes the unique inputs and outputs available at the start of code -/// generation. -#[derive(Debug, Clone)] -pub struct StartOfCodegenOptimization { - program: CompileForm, - code_generator: PrimaryCodegen, -} From a5e0c13943db1829bb4e290bb5c464d8b7daa395 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 12 Sep 2023 10:04:57 -0700 Subject: [PATCH 144/196] Add continued if --- src/compiler/compiler.rs | 11 ++++++++++- src/tests/classic/run.rs | 30 ++++++++++++++++++++++++++++++ src/tests/compiler/preprocessor.rs | 4 +++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index fc196fae5..00f5c7bc5 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -45,10 +45,19 @@ lazy_static! { }; pub static ref ADVANCED_MACROS: String = { indoc! {"( - (defmac if (A B C) + (defmac __chia__primitive__if (A B C) (qq (a (i (unquote A) (com (unquote B)) (com (unquote C))) @)) ) + (defun __chia__if (ARGS) + (__chia__primitive__if (r (r (r ARGS))) + (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (unquote (__chia__if (r (r ARGS)))))) + (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS))))))) + ) + ) + + (defmac if ARGS (qq (a (unquote (__chia__if ARGS)) @))) + (defun __chia__compile-list (args) (if args (c 4 (c (f args) (c (__chia__compile-list (r args)) ()))) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 24681f4e7..be2b99733 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1430,3 +1430,33 @@ fn test_classic_obeys_operator_choice_at_compile_time_version_0() { .to_string(); assert_eq!(compiled, "FAIL: unimplemented operator 48"); } + +#[test] +fn test_continued_if() { + let prog = indoc! {" +(mod X + (include *strict-cl-21*) + + (defun bigatom (Xs Ys) + (if + Xs (concat (f Xs) (bigatom (r Xs) Ys)) + Ys (concat (f Ys) (bigatom (r Ys) ())) + () + ) + ) + + (bigatom (q . (3 4 5)) X) + )"} + .to_string(); + let compiled = do_basic_run(&vec!["run".to_string(), prog]) + .trim() + .to_string(); + let res = do_basic_brun(&vec![ + "brun".to_string(), + compiled, + "(13 99 144)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(res.to_string(), "0x0304050d630090"); +} diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index 9d8947227..d6ede7f50 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -568,7 +568,9 @@ fn test_preprocessor_tours_includes_properly() { let mut includes = Vec::new(); let res = preprocess(opts, &mut includes, parsed[0].clone()).expect("should preprocess"); let expected_lines = &[ - "(defmac if (A B C) (qq (a (i (unquote A) (com (unquote B)) (com (unquote C))) @)))", + "(defmac __chia__primitive__if (A B C) (qq (a (i (unquote A) (com (unquote B)) (com (unquote C))) @)))", + "(defun __chia__if (ARGS) (a (i (r (r (r ARGS))) (com (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (unquote (__chia__if (r (r ARGS))))))) (com (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS))))))))) @))", + "(defmac if ARGS (qq (a (unquote (__chia__if ARGS)) @)))", "(defun __chia__compile-list (args) (a (i args (com (c 4 (c (f args) (c (__chia__compile-list (r args)) ())))) (com ())) @))", "(defmac list ARGS (__chia__compile-list ARGS))", "(defun-inline / (A B) (f (divmod A B)))", From 618ee15d1edfe96c36ec1d2fa4128c48e1db2a83 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 12 Sep 2023 11:38:58 -0700 Subject: [PATCH 145/196] Remove mod+ and left_capture mod, since those aren't used --- src/compiler/comptypes.rs | 7 +------ src/compiler/frontend.rs | 5 ++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index f3e689dc4..009a5fdee 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -451,7 +451,6 @@ pub struct ModAccum { pub loc: Srcloc, pub includes: Vec, pub helpers: Vec, - pub left_capture: bool, pub exp_form: Option, } @@ -488,7 +487,6 @@ impl ModAccum { loc: self.loc.clone(), includes: self.includes.clone(), helpers: self.helpers.clone(), - left_capture: self.left_capture, exp_form: Some(c.clone()), } } @@ -500,7 +498,6 @@ impl ModAccum { loc: self.loc.clone(), includes: new_includes, helpers: self.helpers.clone(), - left_capture: self.left_capture, exp_form: self.exp_form.clone(), } } @@ -513,17 +510,15 @@ impl ModAccum { loc: self.loc.clone(), includes: self.includes.clone(), helpers: hs, - left_capture: self.left_capture, exp_form: self.exp_form.clone(), } } - pub fn new(loc: Srcloc, left_capture: bool) -> ModAccum { + pub fn new(loc: Srcloc) -> ModAccum { ModAccum { loc, includes: Vec::new(), helpers: Vec::new(), - left_capture, exp_form: None, } } diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index ad46f8ed8..aa8cd7ace 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -852,8 +852,7 @@ fn frontend_start( )); } - let is_capture_mod = *mod_atom == b"mod+"; - if is_capture_mod || *mod_atom == b"mod" { + if *mod_atom == b"mod" { let args = Rc::new(x[1].clone()); let body_vec: Vec> = x.iter().skip(2).map(|s| Rc::new(s.clone())).collect(); @@ -861,7 +860,7 @@ fn frontend_start( let ls = preprocess(opts.clone(), includes, body)?; return compile_mod_( - &ModAccum::new(l.clone(), is_capture_mod), + &ModAccum::new(l.clone()), opts.clone(), args, Rc::new(list_to_cons(l, &ls)), From aeecc7506618d45346e49fc6f2b303cddf46e063 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 13 Sep 2023 14:20:58 -0700 Subject: [PATCH 146/196] fmt + clippy --- src/compiler/frontend.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 040dbb74e..346f2fe88 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -253,12 +253,11 @@ fn make_let_bindings( body.loc(), "Bad binding tail ".to_string() + &body.to_string(), )); - let do_atomize = - if opts.dialect().strict { - |a: &SExp| -> SExp { a.atomize() } - } else { - |a: &SExp| -> SExp { a.clone() } - }; + let do_atomize = if opts.dialect().strict { + |a: &SExp| -> SExp { a.atomize() } + } else { + |a: &SExp| -> SExp { a.clone() } + }; match body.borrow() { SExp::Nil(_) => Ok(vec![]), SExp::Cons(_, head, tl) => head From 31ad011daf24ed4bd32a1ea349042596b22b956a Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 14 Sep 2023 11:29:04 -0700 Subject: [PATCH 147/196] Fix rename error which caused clvm ops and callables to be renamed --- src/compiler/rename.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 833706754..ca47292e5 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -234,12 +234,18 @@ fn rename_in_bodyform( }, BodyForm::Call(l, vs, tail) => { - let new_vs = map_m( + let mut new_vs = map_m( &|x: &Rc| -> Result, CompileErr> { Ok(Rc::new(rename_in_bodyform(namemap, x.clone())?)) }, vs, )?; + // Ensure that we haven't renamed the 0th element of a call + // They exist in a separate (global) namespace of callables + // and aren't in the variable scope stack. + if !vs.is_empty() { + new_vs[0] = vs[0].clone(); + } let new_tail = if let Some(t) = tail.as_ref() { Some(Rc::new(rename_in_bodyform(namemap, t.clone())?)) } else { From 8c6c7556c738d7505732eb6879a8dfdafbf98ee5 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 14 Sep 2023 12:47:21 -0700 Subject: [PATCH 148/196] Add comments --- src/compiler/mod.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 63133533a..c6f298712 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -47,16 +47,36 @@ pub struct BasicCompileContext { } impl BasicCompileContext { + /// Get a mutable allocator reference from this compile context. The + /// allocator is used any time we need to execute pure CLVM operators, such + /// as when evaluating macros or constant folding any chialisp expression. fn allocator(&mut self) -> &mut Allocator { &mut self.allocator } + + /// Get the runner this compile context carries. This is used with the + /// allocator above to execute pure CLVM when needed either on behalf of a + /// macro or constant folding. fn runner(&self) -> Rc { self.runner.clone() } + + /// Get the mutable symbol store this compile context carries. During + /// compilation, the compiler records the relationships between objects in + /// the source code and emitted CLVM expressions, along with other useful + /// information. + /// + /// There are times when we're in a subcompile (such as mod expressions when + /// the compile context needs to do swap in or out symbols or transform them + /// on behalf of the child. fn symbols(&mut self) -> &mut HashMap { &mut self.symbols } + /// Given allocator, runner and symbols, move the mutable objects into this + /// BasicCompileContext so it can own them and pass a single mutable + /// reference to itself down the stack. This allows these objects to be + /// queried and used by appropriate machinery. pub fn new( allocator: Allocator, runner: Rc, @@ -70,6 +90,11 @@ impl BasicCompileContext { } } +/// A wrapper that owns a BasicCompileContext and remembers a mutable reference +/// to an allocator and symbols. It is used as a container to swap out these +/// objects for new ones used in an inner compile context. This is used when +/// a subcompile occurs such as when a macro is compiled to CLVM to be executed +/// or an inner mod is compiled. pub struct CompileContextWrapper<'a> { pub allocator: &'a mut Allocator, pub symbols: &'a mut HashMap, @@ -77,6 +102,23 @@ pub struct CompileContextWrapper<'a> { } impl<'a> CompileContextWrapper<'a> { + /// Given an allocator, runner and symbols, hold the mutable references from + /// the code above, swapping content into a new BasicCompileContext this + /// object contains. + /// + /// The new and drop methods both rely on the object's private 'switch' method + /// which swaps the mutable reference to allocator and symbols that the caller + /// holds with the new empty allocator and hashmap held by the inner + /// BasicCompileContext. This allows us to pin the mutable references here, + /// ensuring that this object is the only consumer of these objects when in + /// use, while allowing a new BasicCompileContext to be passed down. The user + /// may inspect, copy, modify etc the inner context before allowing the + /// CompileContextWrapper object to be dropped, which will put the modified + /// objects back in the mutable references given by the user. + /// + /// This object does more in the current (nightly) code, such as carrying the + /// optimizer, which is modified when an inner compile has a different sigil + /// and must be optimized differently. pub fn new( allocator: &'a mut Allocator, runner: Rc, @@ -96,12 +138,19 @@ impl<'a> CompileContextWrapper<'a> { wrapper } + /// Swap allocator and symbols with the ones in self.context. This has the + /// effect of making the inner context hold the same information that would + /// have been passed down in these members had it come from the caller's + /// perspective. Useful when compile context has more fields and needs + /// to change for a consumer down the stack. fn switch(&mut self) { swap(self.allocator, &mut self.context.allocator); swap(self.symbols, &mut self.context.symbols); } } +/// Drop CompileContextWrapper reverts the contained objects back to the ones +/// owned by the caller. impl<'a> Drop for CompileContextWrapper<'a> { fn drop(&mut self) { self.switch(); From b48b921e82635fdf96f8df69680007f6b787ab2f Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 14 Sep 2023 12:55:28 -0700 Subject: [PATCH 149/196] Add comments, reverse some not-yet-needed changes --- src/classic/clvm_tools/clvmc.rs | 36 ++++++--------------------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index d51162373..b4892f1b8 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -38,9 +38,8 @@ pub fn write_sym_output( .map(|_| ()) } -pub fn compile_clvm_text_maybe_opt( +pub fn compile_clvm_text( allocator: &mut Allocator, - do_optimize: bool, opts: Rc, symbol_table: &mut HashMap, text: &str, @@ -53,19 +52,15 @@ pub fn compile_clvm_text_maybe_opt( let dialect = detect_modern(allocator, assembled_sexp); // Now the stepping is optional (None for classic) but we may communicate // other information in dialect as well. + // + // I think stepping is a good name for the number below as dialect is going + // to get more members that are somewhat independent. if let Some(stepping) = dialect.stepping { let runner = Rc::new(DefaultProgramRunner::new()); - let opts = opts - .set_dialect(dialect) - .set_optimize(do_optimize || stepping > 22) - .set_frontend_opt(stepping == 22); + let opts = opts.set_optimize(true).set_frontend_opt(stepping > 21); let unopt_res = compile_file(allocator, runner.clone(), opts, text, symbol_table); - let res = if do_optimize { - unopt_res.and_then(|x| run_optimizer(allocator, runner, Rc::new(x))) - } else { - unopt_res.map(Rc::new) - }; + let res = unopt_res.and_then(|x| run_optimizer(allocator, runner, Rc::new(x))); res.and_then(|x| { convert_to_clvm_rs(allocator, x).map_err(|r| match r { @@ -87,25 +82,6 @@ pub fn compile_clvm_text_maybe_opt( } } -pub fn compile_clvm_text( - allocator: &mut Allocator, - opts: Rc, - symbol_table: &mut HashMap, - text: &str, - input_path: &str, - classic_with_opts: bool, -) -> Result { - compile_clvm_text_maybe_opt( - allocator, - true, - opts, - symbol_table, - text, - input_path, - classic_with_opts, - ) -} - pub fn compile_clvm_inner( allocator: &mut Allocator, opts: Rc, From 2a7902dfc4be6b76dcea47eb8539f7caa695bd01 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Tue, 19 Sep 2023 20:25:23 +0100 Subject: [PATCH 150/196] Opt for source-based code coverage. --- .github/workflows/build-test.yml | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 02c61ab73..409609482 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -337,11 +337,26 @@ jobs: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: - toolchain: nightly - - name: Install tarpaulin - run: cargo +nightly install cargo-tarpaulin - - name: Run tarpaulin - run: cargo tarpaulin --no-dead-code --engine llvm --workspace --all-features --ignore-panics --out Lcov + toolchain: stable + - name: Run for coverage + run: | + sudo apt-get update + sudo apt-get install lcov -y + rustup component add llvm-tools-preview + cargo install grcov + export RUSTFLAGS="-Cinstrument-coverage" + export LLVM_PROFILE_FILE=$(pwd)/target/clvm_tools_rs-%p-%m.profraw + export CARGO_TARGET_DIR=$(pwd)/target + cargo test --release --workspace + python -m venv venv + source venv/bin/activate + git clone https://github.com/Chia-Network/clvm_tools.git --branch=main --single-branch + pip install ./clvm_tools + pip install maturin pytest + maturin develop --release + (cd resources/tests/cmdline/tests && pytest) + grcov . --binary-path target -s . --branch --ignore-not-existing --ignore='*/.cargo/*' --ignore='*/tests/*' -o rust_cov.info + python -c 'with open("rust_cov.info") as f: lines = [l for l in f if not (l.startswith("DA:") and int(l.split(",")[1].strip()) >= 2**63)]; open("lcov.info", "w").writelines(lines)' - name: Upload to Coveralls uses: coverallsapp/github-action@v2 if: always() From 965e398afed976ca5161cd7cc80b40b1fdbb4691 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 20 Sep 2023 02:47:31 -0700 Subject: [PATCH 151/196] Capture what i think is the smallest possible slice of optimizer strategy --- src/compiler/codegen.rs | 22 +- src/compiler/compiler.rs | 20 +- src/compiler/comptypes.rs | 13 +- src/compiler/evaluate.rs | 12 +- src/compiler/frontend.rs | 5 +- src/compiler/mod.rs | 15 + src/compiler/optimize.rs | 125 ----- src/compiler/optimize/mod.rs | 767 ++++++++++++++++++++++++++++++ src/compiler/optimize/strategy.rs | 170 +++++++ src/compiler/rename.rs | 21 +- 10 files changed, 1002 insertions(+), 168 deletions(-) delete mode 100644 src/compiler/optimize.rs create mode 100644 src/compiler/optimize/mod.rs create mode 100644 src/compiler/optimize/strategy.rs diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index f224c6852..886ca7ea8 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -14,14 +14,14 @@ use crate::compiler::comptypes::{ fold_m, join_vecs_to_string, list_to_cons, Binding, BindingPattern, BodyForm, CallSpec, Callable, CompileErr, CompileForm, CompiledCode, CompilerOpts, ConstantKind, DefunCall, DefunData, HelperForm, InlineFunction, LetData, LetFormInlineHint, LetFormKind, PrimaryCodegen, - RawCallSpec, + RawCallSpec, SyntheticType, }; use crate::compiler::debug::{build_swap_table_mut, relabel}; use crate::compiler::evaluate::{Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::frontend::{compile_bodyform, make_provides_set}; use crate::compiler::gensym::gensym; use crate::compiler::inline::{replace_in_inline, synthesize_args}; -use crate::compiler::optimize::optimize_expr; +use crate::compiler::optimize::{get_optimizer, optimize_expr}; use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::{decode_string, SExp}; @@ -522,8 +522,9 @@ pub fn do_mod_codegen( let without_env = opts.set_start_env(None).set_in_defun(false); let mut throwaway_symbols = HashMap::new(); let runner = context.runner(); + let optimizer = get_optimizer(&program.loc, opts.clone())?; let mut context_wrapper = - CompileContextWrapper::new(context.allocator(), runner.clone(), &mut throwaway_symbols); + CompileContextWrapper::new(context.allocator(), runner.clone(), &mut throwaway_symbols, optimizer); let code = codegen(&mut context_wrapper.context, without_env, program)?; Ok(CompiledCode( program.loc.clone(), @@ -813,7 +814,7 @@ fn generate_let_defun( // binary size, when permitted. Sometimes the user will signal a // preference. should_inline_let(inline_hint), - DefunData { + Box::new(DefunData { loc: l.clone(), nl: l, kw: kwl, @@ -821,7 +822,8 @@ fn generate_let_defun( orig_args: inner_function_args.clone(), args: inner_function_args, body, - }, + synthetic: Some(SyntheticType::NoInlinePreference), + }), ) } @@ -1127,15 +1129,11 @@ pub fn process_helper_let_bindings(helpers: &[HelperForm]) -> Result, ) -> Result { - let pre_forms = parse_sexp(Srcloc::start(&opts.filename()), content.bytes())?; - let mut context_wrapper = CompileContextWrapper::new(allocator, runner, symbol_table); + let loc = Srcloc::start(&opts.filename()); + let optimizer = get_optimizer(&loc, opts.clone())?; + let pre_forms = parse_sexp(loc, content.bytes())?; + let mut context_wrapper = CompileContextWrapper::new(allocator, runner, symbol_table, optimizer); compile_pre_forms(&mut context_wrapper.context, opts, &pre_forms) } @@ -351,7 +350,8 @@ impl CompilerOpts for DefaultCompilerOpts { symbol_table: &mut HashMap, ) -> Result { let me = Rc::new(self.clone()); - let mut context_wrapper = CompileContextWrapper::new(allocator, runner, symbol_table); + let optimizer = get_optimizer(&sexp.loc(), me.clone())?; + let mut context_wrapper = CompileContextWrapper::new(allocator, runner, symbol_table, optimizer); compile_pre_forms(&mut context_wrapper.context, me, &[sexp]) } } diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 0d0c7a84e..1c26ac945 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -174,6 +174,15 @@ pub enum BodyForm { Mod(Srcloc, CompileForm), } +/// Convey information about synthetically generated helper forms. +#[derive(Clone, Debug, Serialize)] +pub enum SyntheticType { + NoInlinePreference, + MaybeRecursive, + WantInline, + WantNonInline, +} + /// The information needed to know about a defun. Whether it's inline is left in /// the HelperForm. #[derive(Clone, Debug, Serialize)] @@ -192,6 +201,8 @@ pub struct DefunData { pub args: Rc, /// The body expression of the defun. pub body: Rc, + /// Whether this defun was created during desugaring. + pub synthetic: Option, } /// Specifies the information extracted from a macro definition allowing the @@ -250,7 +261,7 @@ pub enum HelperForm { /// A macro definition (see DefmacData). Defmacro(DefmacData), /// A function definition (see DefunData). - Defun(bool, DefunData), + Defun(bool, Box), } /// To what purpose is the file included. diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index fc5fac818..67bb0b0d9 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -17,6 +17,7 @@ use crate::compiler::comptypes::{ LetData, LetFormInlineHint, LetFormKind, }; use crate::compiler::frontend::frontend; +use crate::compiler::optimize::get_optimizer; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; @@ -477,10 +478,14 @@ fn is_apply_atom(h: Rc) -> bool { match_atom_to_prim(vec![b'a'], 2, h) } -fn is_i_atom(h: Rc) -> bool { +pub fn is_i_atom(h: Rc) -> bool { match_atom_to_prim(vec![b'i'], 3, h) } +pub fn is_not_atom(h: Rc) -> bool { + match_atom_to_prim(b"not".to_vec(), 32, h) +} + fn is_cons_atom(h: Rc) -> bool { match_atom_to_prim(vec![b'c'], 4, h) } @@ -1221,11 +1226,12 @@ impl<'info> Evaluator { )), } } - BodyForm::Mod(_, program) => { + BodyForm::Mod(l, program) => { // A mod form yields the compiled code. let mut symbols = HashMap::new(); + let optimizer = get_optimizer(l, self.opts.clone())?; let mut context_wrapper = - CompileContextWrapper::new(allocator, self.runner.clone(), &mut symbols); + CompileContextWrapper::new(allocator, self.runner.clone(), &mut symbols, optimizer); let code = codegen(&mut context_wrapper.context, self.opts.clone(), program)?; Ok(Rc::new(BodyForm::Quoted(code))) } diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index ad24d0a24..4b680d8d4 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -591,7 +591,7 @@ fn compile_defun(opts: Rc, data: CompileDefun) -> Result, data: CompileDefun) -> Result, pub symbols: HashMap, + pub optimizer: Box, } impl BasicCompileContext { @@ -81,11 +84,13 @@ impl BasicCompileContext { allocator: Allocator, runner: Rc, symbols: HashMap, + optimizer: Box, ) -> Self { BasicCompileContext { allocator, runner, symbols, + optimizer, } } } @@ -123,11 +128,13 @@ impl<'a> CompileContextWrapper<'a> { allocator: &'a mut Allocator, runner: Rc, symbols: &'a mut HashMap, + optimizer: Box, ) -> Self { let bcc = BasicCompileContext { allocator: Allocator::new(), runner, symbols: HashMap::new(), + optimizer, }; let mut wrapper = CompileContextWrapper { allocator, @@ -156,3 +163,11 @@ impl<'a> Drop for CompileContextWrapper<'a> { self.switch(); } } + +/// Describes the unique inputs and outputs available at the start of code +/// generation. +#[derive(Debug, Clone)] +pub struct StartOfCodegenOptimization { + program: CompileForm, + code_generator: PrimaryCodegen, +} diff --git a/src/compiler/optimize.rs b/src/compiler/optimize.rs deleted file mode 100644 index 84a262042..000000000 --- a/src/compiler/optimize.rs +++ /dev/null @@ -1,125 +0,0 @@ -use std::borrow::Borrow; -use std::rc::Rc; - -use clvm_rs::allocator::Allocator; - -use crate::classic::clvm_tools::stages::stage_0::TRunProgram; - -use crate::compiler::clvm::run; -use crate::compiler::codegen::get_callable; -use crate::compiler::comptypes::{BodyForm, Callable, CompilerOpts, PrimaryCodegen}; -use crate::compiler::sexp::SExp; -use crate::compiler::srcloc::Srcloc; -use crate::util::u8_from_number; - -const CONST_FOLD_LIMIT: usize = 10000000; - -fn is_at_form(head: Rc) -> bool { - match head.borrow() { - BodyForm::Value(SExp::Atom(_, a)) => a.len() == 1 && a[0] == b'@', - _ => false, - } -} - -/// At this point, very rudimentary constant folding on body expressions. -pub fn optimize_expr( - allocator: &mut Allocator, - opts: Rc, - runner: Rc, - compiler: &PrimaryCodegen, - body: Rc, -) -> Option<(bool, Rc)> { - match body.borrow() { - BodyForm::Quoted(_) => Some((true, body)), - BodyForm::Call(l, forms, None) => { - // () evaluates to () - if forms.is_empty() { - return Some((true, body)); - } else if is_at_form(forms[0].clone()) { - return None; - } - - let mut examine_call = |al: Srcloc, an: &Vec| { - get_callable( - opts.clone(), - compiler, - l.clone(), - Rc::new(SExp::Atom(al, an.to_vec())), - ) - .map(|calltype| match calltype { - // A macro invocation emits a bodyform, which we - // run back through the frontend and check. - Callable::CallMacro(_l, _) => None, - // A function is constant if its body is a constant - // expression or all its arguments are constant and - // its body doesn't include an environment reference. - Callable::CallDefun(_l, _target) => None, - // A primcall is constant if its arguments are constant - Callable::CallPrim(l, _) => { - let mut constant = true; - let optimized_args: Vec<(bool, Rc)> = forms - .iter() - .skip(1) - .map(|a| { - let optimized = optimize_expr( - allocator, - opts.clone(), - runner.clone(), - compiler, - a.clone(), - ); - constant = constant - && optimized.as_ref().map(|x| x.0).unwrap_or_else(|| false); - optimized - .map(|x| (x.0, x.1)) - .unwrap_or_else(|| (false, a.clone())) - }) - .collect(); - - let mut result_list = vec![forms[0].clone()]; - let mut replaced_args = - optimized_args.iter().map(|x| x.1.clone()).collect(); - result_list.append(&mut replaced_args); - // Calling a primitive. - let code = BodyForm::Call(l.clone(), result_list, None); - - if constant { - run( - allocator, - runner.clone(), - opts.prim_map(), - code.to_sexp(), - Rc::new(SExp::Nil(l)), - Some(CONST_FOLD_LIMIT), - ) - .map(|x| { - let x_borrow: &SExp = x.borrow(); - Some((true, Rc::new(BodyForm::Quoted(x_borrow.clone())))) - }) - .unwrap_or_else(|_| Some((false, Rc::new(code)))) - } else { - Some((false, Rc::new(code))) - } - } - _ => None, - }) - .unwrap_or_else(|_| None) - }; - - match forms[0].borrow() { - BodyForm::Value(SExp::Integer(al, an)) => { - examine_call(al.clone(), &u8_from_number(an.clone())) - } - BodyForm::Value(SExp::QuotedString(al, _, an)) => examine_call(al.clone(), an), - BodyForm::Value(SExp::Atom(al, an)) => examine_call(al.clone(), an), - _ => None, - } - } - BodyForm::Call(_l, _forms, Some(_)) => None, - BodyForm::Value(SExp::Integer(l, i)) => Some(( - true, - Rc::new(BodyForm::Quoted(SExp::Integer(l.clone(), i.clone()))), - )), - _ => None, - } -} diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs new file mode 100644 index 000000000..01b6bf99d --- /dev/null +++ b/src/compiler/optimize/mod.rs @@ -0,0 +1,767 @@ +pub mod strategy; + +#[cfg(test)] +use num_bigint::ToBigInt; + +use std::borrow::Borrow; +use std::collections::HashMap; +use std::rc::Rc; + +use clvm_rs::allocator::Allocator; + +#[cfg(test)] +use crate::classic::clvm::__type_compatibility__::bi_one; +use crate::classic::clvm::__type_compatibility__::bi_zero; + +use crate::classic::clvm_tools::stages::stage_0::TRunProgram; +use crate::classic::clvm_tools::stages::stage_2::optimize::optimize_sexp; + +use crate::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, run}; +use crate::compiler::codegen::{codegen, do_mod_codegen, get_callable}; +use crate::compiler::comptypes::{ + BodyForm, CallSpec, Callable, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, + PrimaryCodegen, SyntheticType, +}; +use crate::compiler::evaluate::{ + build_reflex_captures, dequote, is_i_atom, is_not_atom, Evaluator, EVAL_STACK_LIMIT, +}; +use crate::compiler::optimize::strategy::ExistingStrategy; +use crate::compiler::runtypes::RunFailure; +#[cfg(test)] +use crate::compiler::sexp::parse_sexp; +use crate::compiler::sexp::SExp; +use crate::compiler::srcloc::Srcloc; +use crate::compiler::BasicCompileContext; +use crate::compiler::CompileContextWrapper; +use crate::compiler::StartOfCodegenOptimization; +use crate::util::u8_from_number; + +const CONST_FOLD_LIMIT: usize = 10000000; + +/// Represents a code generator level optimization result. +/// If revised_definition is different from the one we already have, the compiler +/// must re-generate at least functions that depend on this one. +#[derive(Default, Debug, Clone)] +pub struct CodegenOptimizationResult { + /// Revised code generator object, if given. + pub revised_code_generator: Option, + /// If present, the definition of the helperform, if provided, was changed. + pub revised_definition: Option, + /// If present, each key represents the shatree of an environment part that + /// was rewriten along with its new definition. + pub revised_environment: Option, Rc>>, + /// Final generated code if different. + pub code: Option>, +} + +/// Make a formal interface that represents all kinds of optimization we can do. +/// This includes these possible things: +/// +/// - Frontend: +/// - Simplification +/// - Constant folding +/// - Inlining and deinlining +/// - SSA optimizations +/// - Deduplication +/// - Constant term propogation +/// - ... etc +/// - Argument list changes which simplify code +/// - Capture removal +/// - Pattern based inlining in loops +/// +/// - Start of codegen +/// - Environment layout optimization +/// - Dead code/constant elimination +/// - Leaf function optimization +/// - Leaf main optimization +/// +/// - During codegen +/// - Function level code optimizations +/// - Constant compression +/// - Nil and quote simplification +/// - Constant folding +/// - Path folding for (r and (f and composed paths +/// - Cons simplification +/// - Apply elision +/// +/// Global optimization must be performed when the code generator is requesting +/// optimizations on the main expression, therefore there is no post-code generator +/// optimization in this scheme. +/// +pub trait Optimization { + /// Represents frontend optimizations + fn frontend_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + cf: CompileForm, + ) -> Result; + + /// Represents optimization we should do after desugaring, such as deinlining + fn post_desugar_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + cf: CompileForm, + ) -> Result; + + /// Represents start of codegen optimizations + /// PrimaryCodegen has computed the environment it wants to use but hasn't + /// generated any code that depends on it yet. + fn start_of_codegen_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + to_optimize: StartOfCodegenOptimization, + ) -> Result; + + /// Optimize macro bodies. + fn macro_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + code: Rc, + ) -> Result, CompileErr>; + + fn defun_body_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + codegen: &PrimaryCodegen, + defun: &DefunData, + ) -> Result, CompileErr>; + + fn post_codegen_function_optimize( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + helper: Option<&HelperForm>, + code: Rc, + ) -> Result, CompileErr>; + + fn pre_final_codegen_optimize( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + codegen: &PrimaryCodegen, + ) -> Result, CompileErr>; + + fn post_codegen_output_optimize( + &mut self, + opts: Rc, + generated: SExp, + ) -> Result; + + fn duplicate(&self) -> Box; +} + +fn is_at_form(head: Rc) -> bool { + match head.borrow() { + BodyForm::Value(SExp::Atom(_, a)) => a.len() == 1 && a[0] == b'@', + _ => false, + } +} + +fn get_primitive_quoted_value(form: Rc) -> Option> { + if let SExp::Cons(l, a, b) = form.borrow() { + let a_borrowed: &SExp = a.borrow(); + if a_borrowed == &SExp::Atom(l.clone(), vec![1]) { + return Some(b.clone()); + } + } + + None +} + +// Return a score for sexp size. +pub fn sexp_scale(sexp: &SExp) -> u64 { + match sexp { + SExp::Cons(_, a, b) => { + let a_scale = sexp_scale(a.borrow()); + let b_scale = sexp_scale(b.borrow()); + 1_u64 + a_scale + b_scale + } + SExp::Nil(_) => 1, + SExp::QuotedString(_, _, s) => 1_u64 + s.len() as u64, + SExp::Atom(_, n) => 1_u64 + n.len() as u64, + SExp::Integer(_, i) => { + let raw_bits = i.bits(); + let use_bits = if raw_bits > 0 { raw_bits - 1 } else { 0 }; + let bytes = use_bits / 8; + 1_u64 + bytes + } + } +} + +#[test] +fn test_sexp_scale_increases_with_atom_size() { + let l = Srcloc::start("*test*"); + assert!( + sexp_scale(&SExp::Integer(l.clone(), bi_one())) + < sexp_scale(&SExp::Integer(l, 1000000_u32.to_bigint().unwrap())) + ); +} + +fn is_not_condition(bf: &BodyForm) -> Option> { + // Checking for a primitive so no tail. + if let BodyForm::Call(_, parts, None) = bf { + if parts.len() != 2 { + return None; + } + + if is_not_atom(parts[0].to_sexp()) { + return Some(parts[1].clone()); + } + } + + None +} + +/// Changes (i (not c) a b) into (i c b a) +fn condition_invert_optimize( + opts: Rc, + loc: &Srcloc, + forms: &[Rc], +) -> Option { + if let Some(res) = opts.dialect().stepping { + // Only perform on chialisp above the appropriate stepping. + if res >= 23 { + if forms.len() != 4 { + return None; + } + + if !is_i_atom(forms[0].to_sexp()) { + return None; + } + + // We have a (not cond) + if let Some(condition) = is_not_condition(forms[1].borrow()) { + return Some(BodyForm::Call( + loc.clone(), + vec![ + forms[0].clone(), + condition, + forms[3].clone(), + forms[2].clone(), + ], + None, + )); + } + } + } + + None +} + +/// If a function is called with all constant arguments, we compose the program +/// that runs that function and run it. +/// +/// The result is the constant result of invoking the function. +fn constant_fun_result( + allocator: &mut Allocator, + opts: Rc, + runner: Rc, + compiler: &PrimaryCodegen, + call_spec: &CallSpec, +) -> Option> { + if let Some(res) = opts.dialect().stepping { + if res >= 23 { + let mut constant = true; + let optimized_args: Vec<(bool, Rc)> = call_spec + .args + .iter() + .skip(1) + .map(|a| { + let optimized = + optimize_expr(allocator, opts.clone(), runner.clone(), compiler, a.clone()); + constant = constant && optimized.as_ref().map(|x| x.0).unwrap_or_else(|| false); + optimized + .map(|x| (x.0, x.1)) + .unwrap_or_else(|| (false, a.clone())) + }) + .collect(); + + let optimized_tail: Option<(bool, Rc)> = call_spec.tail.as_ref().map(|t| { + let optimized = + optimize_expr(allocator, opts.clone(), runner.clone(), compiler, t.clone()); + constant = constant && optimized.as_ref().map(|x| x.0).unwrap_or_else(|| false); + optimized + .map(|x| (x.0, x.1)) + .unwrap_or_else(|| (false, t.clone())) + }); + + if !constant { + return None; + } + + let compiled_body = { + let to_compile = CompileForm { + loc: call_spec.loc.clone(), + include_forms: Vec::new(), + helpers: compiler.original_helpers.clone(), + args: Rc::new(SExp::Atom(call_spec.loc.clone(), b"__ARGS__".to_vec())), + exp: Rc::new(BodyForm::Call( + call_spec.loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(call_spec.loc.clone(), vec![2]))), + Rc::new(BodyForm::Value(SExp::Atom( + call_spec.loc.clone(), + call_spec.name.to_vec(), + ))), + Rc::new(BodyForm::Value(SExp::Atom( + call_spec.loc.clone(), + b"__ARGS__".to_vec(), + ))), + ], + // Proper call: we're calling 'a' on behalf of our + // single capture argument. + None, + )), + }; + let optimizer = if let Ok(res) = get_optimizer(&call_spec.loc, opts.clone()) { + res + } else { + return None; + }; + + let mut symbols = HashMap::new(); + let mut wrapper = + CompileContextWrapper::new(allocator, runner.clone(), &mut symbols, optimizer); + + if let Ok(code) = codegen(&mut wrapper.context, opts.clone(), &to_compile) { + code + } else { + return None; + } + }; + + // Reified args reflect the actual ABI shape with a tail if any. + let mut reified_args = if let Some((_, t)) = optimized_tail { + if let Ok(res) = dequote(call_spec.loc.clone(), t) { + res + } else { + return None; + } + } else { + Rc::new(SExp::Nil(call_spec.loc.clone())) + }; + for (_, v) in optimized_args.iter().rev() { + let unquoted = if let Ok(res) = dequote(call_spec.loc.clone(), v.clone()) { + res + } else { + return None; + }; + reified_args = Rc::new(SExp::Cons(call_spec.loc.clone(), unquoted, reified_args)); + } + let borrowed_args: &SExp = reified_args.borrow(); + let new_body = BodyForm::Call( + call_spec.loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(call_spec.loc.clone(), vec![2]))), + Rc::new(BodyForm::Quoted(compiled_body)), + Rc::new(BodyForm::Quoted(borrowed_args.clone())), + ], + // The constructed call is proper because we're feeding something + // we constructed above. + None, + ); + + return Some(Rc::new(new_body)); + } + } + + None +} + +/// At this point, very rudimentary constant folding on body expressions. +pub fn optimize_expr( + allocator: &mut Allocator, + opts: Rc, + runner: Rc, + compiler: &PrimaryCodegen, + body: Rc, +) -> Option<(bool, Rc)> { + match body.borrow() { + BodyForm::Quoted(_) => Some((true, body)), + BodyForm::Call(l, forms, tail) => { + // () evaluates to () + if forms.is_empty() { + return Some((true, body)); + } else if is_at_form(forms[0].clone()) { + return None; + } + + let examine_call = |al: Srcloc, an: &Vec| { + get_callable( + opts.clone(), + compiler, + l.clone(), + Rc::new(SExp::Atom(al, an.to_vec())), + ) + .map(|calltype| match calltype { + // A macro invocation emits a bodyform, which we + // run back through the frontend and check. + Callable::CallMacro(_l, _) => None, + // A function is constant if its body is a constant + // expression or all its arguments are constant and + // its body doesn't include an environment reference. + Callable::CallDefun(l, _target) => { + if let Some(constant_invocation) = constant_fun_result( + allocator, + opts.clone(), + runner.clone(), + compiler, + &CallSpec { + loc: l, + name: an, + args: forms, + tail: tail.clone(), + original: body.clone(), + }, + ) { + return Some( + optimize_expr( + allocator, + opts.clone(), + runner, + compiler, + constant_invocation.clone(), + ) + .map(|(_, optimize)| (true, optimize)) + .unwrap_or_else(|| (true, constant_invocation)), + ); + } + + None + } + // A primcall is constant if its arguments are constant + Callable::CallPrim(l, _) => { + let mut constant = true; + + if let Some(not_invert) = condition_invert_optimize(opts.clone(), &l, forms) + { + return Some( + optimize_expr( + allocator, + opts.clone(), + runner.clone(), + compiler, + Rc::new(not_invert.clone()), + ) + .map(|(_, optimize)| (true, optimize)) + .unwrap_or_else(|| (true, Rc::new(not_invert))), + ); + } + + let optimized_args: Vec<(bool, Rc)> = forms + .iter() + .skip(1) + .map(|a| { + let optimized = optimize_expr( + allocator, + opts.clone(), + runner.clone(), + compiler, + a.clone(), + ); + constant = constant + && optimized.as_ref().map(|x| x.0).unwrap_or_else(|| false); + optimized + .map(|x| (x.0, x.1)) + .unwrap_or_else(|| (false, a.clone())) + }) + .collect(); + + let mut result_list = vec![forms[0].clone()]; + let mut replaced_args = + optimized_args.iter().map(|x| x.1.clone()).collect(); + result_list.append(&mut replaced_args); + // Primitive call: no tail. + let code = BodyForm::Call(l.clone(), result_list, None); + + if constant { + run( + allocator, + runner.clone(), + opts.prim_map(), + code.to_sexp(), + Rc::new(SExp::Nil(l)), + Some(CONST_FOLD_LIMIT), + ) + .map(|x| { + let x_borrow: &SExp = x.borrow(); + Some((true, Rc::new(BodyForm::Quoted(x_borrow.clone())))) + }) + .unwrap_or_else(|_| Some((false, Rc::new(code)))) + } else { + Some((false, Rc::new(code))) + } + } + _ => None, + }) + .unwrap_or_else(|_| None) + }; + + match forms[0].borrow() { + BodyForm::Value(SExp::Integer(al, an)) => { + examine_call(al.clone(), &u8_from_number(an.clone())) + } + BodyForm::Value(SExp::QuotedString(al, _, an)) => examine_call(al.clone(), an), + BodyForm::Value(SExp::Atom(al, an)) => examine_call(al.clone(), an), + _ => None, + } + } + BodyForm::Value(SExp::Integer(l, i)) => Some(( + true, + Rc::new(BodyForm::Quoted(SExp::Integer(l.clone(), i.clone()))), + )), + BodyForm::Mod(l, cf) => { + if let Some(stepping) = opts.dialect().stepping { + if stepping >= 23 { + let mut throwaway_symbols = HashMap::new(); + if let Ok(optimizer) = get_optimizer(l, opts.clone()) { + let mut wrapper = CompileContextWrapper::new( + allocator, + runner, + &mut throwaway_symbols, + optimizer, + ); + if let Ok(compiled) = do_mod_codegen(&mut wrapper.context, opts.clone(), cf) + { + if let Some(body) = get_primitive_quoted_value(compiled.1) { + let borrowed_body: &SExp = body.borrow(); + return Some(( + true, + Rc::new(BodyForm::Quoted(borrowed_body.clone())), + )); + } + } + } + } + } + + None + } + _ => None, + } +} + +// If (1) appears anywhere outside of a quoted expression, it can be replaced with +// () since nil yields itself. +fn null_optimization(sexp: Rc, spine: bool) -> (bool, Rc) { + if let SExp::Cons(l, a, b) = sexp.borrow() { + if let SExp::Atom(_, name) = a.atomize() { + if (name == vec![1] || name == b"q") && !spine { + let b_empty = match b.borrow() { + SExp::Atom(_, tail) => tail.is_empty(), + SExp::QuotedString(_, _, q) => q.is_empty(), + SExp::Integer(_, i) => *i == bi_zero(), + SExp::Nil(_) => true, + _ => false, + }; + + if b_empty { + return (true, b.clone()); + } else { + return (false, sexp); + } + } + } + + let (oa, opt_a) = null_optimization(a.clone(), false); + let (ob, opt_b) = null_optimization(b.clone(), true); + + if oa || ob { + return (true, Rc::new(SExp::Cons(l.clone(), opt_a, opt_b))); + } + } + + (false, sexp) +} + +#[test] +fn test_null_optimization_basic() { + let loc = Srcloc::start("*test*"); + let parsed = parse_sexp(loc.clone(), "(2 (1 1) (4 (1) 1))".bytes()).expect("should parse"); + let (did_work, optimized) = null_optimization(parsed[0].clone(), true); + assert!(did_work); + assert_eq!(optimized.to_string(), "(2 (1 1) (4 () 1))"); +} + +#[test] +fn test_null_optimization_skips_quoted() { + let loc = Srcloc::start("*test*"); + let parsed = parse_sexp(loc.clone(), "(2 (1 (1) (1) (1)) (1))".bytes()).expect("should parse"); + let (did_work, optimized) = null_optimization(parsed[0].clone(), true); + assert!(did_work); + assert_eq!(optimized.to_string(), "(2 (1 (1) (1) (1)) ())"); +} + +#[test] +fn test_null_optimization_ok_not_doing_anything() { + let loc = Srcloc::start("*test*"); + let parsed = parse_sexp(loc.clone(), "(2 (1 (1) (1) (1)) (3))".bytes()).expect("should parse"); + let (did_work, optimized) = null_optimization(parsed[0].clone(), true); + assert!(!did_work); + assert_eq!(optimized.to_string(), "(2 (1 (1) (1) (1)) (3))"); +} + +// Should take a desugared program. +pub fn deinline_opt( + context: &mut BasicCompileContext, + opts: Rc, + mut compileform: CompileForm, +) -> Result { + let mut best_compileform = compileform.clone(); + let generated_program = codegen(context, opts.clone(), &best_compileform)?; + let mut metric = sexp_scale(&generated_program); + let flip_helper = |h: &mut HelperForm| { + if let HelperForm::Defun(inline, defun) = h { + if matches!(&defun.synthetic, Some(SyntheticType::NoInlinePreference)) { + *h = HelperForm::Defun(!*inline, defun.clone()); + return true; + } + } + + false + }; + + loop { + let start_metric = metric; + + for i in 0..compileform.helpers.len() { + // Try flipped. + let old_helper = compileform.helpers[i].clone(); + if !flip_helper(&mut compileform.helpers[i]) { + continue; + } + + let maybe_smaller_program = codegen(context, opts.clone(), &compileform)?; + let new_metric = sexp_scale(&maybe_smaller_program); + + // Don't keep this change if it made things worse. + if new_metric >= metric { + compileform.helpers[i] = old_helper; + } else { + metric = new_metric; + best_compileform = compileform.clone(); + } + } + + if start_metric == metric { + break; + } + } + + Ok(best_compileform) +} + +fn fe_opt( + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + compileform: CompileForm, +) -> Result { + let evaluator = Evaluator::new(opts.clone(), runner.clone(), compileform.helpers.clone()); + let mut optimized_helpers: Vec = Vec::new(); + for h in compileform.helpers.iter() { + match h { + HelperForm::Defun(inline, defun) => { + let mut env = HashMap::new(); + build_reflex_captures(&mut env, defun.args.clone()); + let body_rc = evaluator.shrink_bodyform( + allocator, + defun.args.clone(), + &env, + defun.body.clone(), + true, + Some(EVAL_STACK_LIMIT), + )?; + let new_helper = HelperForm::Defun( + *inline, + Box::new(DefunData { + loc: defun.loc.clone(), + nl: defun.nl.clone(), + kw: defun.kw.clone(), + name: defun.name.clone(), + args: defun.args.clone(), + orig_args: defun.orig_args.clone(), + synthetic: defun.synthetic.clone(), + body: body_rc.clone(), + }), + ); + optimized_helpers.push(new_helper); + } + obj => { + optimized_helpers.push(obj.clone()); + } + } + } + let new_evaluator = Evaluator::new(opts.clone(), runner.clone(), optimized_helpers.clone()); + + let shrunk = new_evaluator.shrink_bodyform( + allocator, + Rc::new(SExp::Nil(compileform.args.loc())), + &HashMap::new(), + compileform.exp.clone(), + true, + Some(EVAL_STACK_LIMIT), + )?; + + Ok(CompileForm { + helpers: optimized_helpers.clone(), + exp: shrunk, + ..compileform + }) +} + +pub fn run_optimizer( + allocator: &mut Allocator, + runner: Rc, + r: Rc, +) -> Result, CompileErr> { + let to_clvm_rs = convert_to_clvm_rs(allocator, r.clone()) + .map(|x| (r.loc(), x)) + .map_err(|e| match e { + RunFailure::RunErr(l, e) => CompileErr(l, e), + RunFailure::RunExn(s, e) => CompileErr(s, format!("exception {e}\n")), + })?; + + let optimized = optimize_sexp(allocator, to_clvm_rs.1, runner) + .map_err(|e| CompileErr(to_clvm_rs.0.clone(), e.1)) + .map(|x| (to_clvm_rs.0, x))?; + + convert_from_clvm_rs(allocator, optimized.0, optimized.1).map_err(|e| match e { + RunFailure::RunErr(l, e) => CompileErr(l, e), + RunFailure::RunExn(s, e) => CompileErr(s, format!("exception {e}\n")), + }) +} + +/// Produce the optimization strategy specified by the compiler opts we're given. +pub fn get_optimizer( + loc: &Srcloc, + opts: Rc, +) -> Result, CompileErr> { + if let Some(s) = opts.dialect().stepping { + if s < 21 { + return Err(CompileErr( + loc.clone(), + format!("minimum language stepping is 21, {s} specified"), + )); + } else if s > 22 { + return Err(CompileErr( + loc.clone(), + format!("maximum language stepping is 22 at this time, {s} specified"), + )); + } + } + + Ok(Box::new(ExistingStrategy::new())) +} diff --git a/src/compiler/optimize/strategy.rs b/src/compiler/optimize/strategy.rs new file mode 100644 index 000000000..9b7ecd6d9 --- /dev/null +++ b/src/compiler/optimize/strategy.rs @@ -0,0 +1,170 @@ +use std::borrow::Borrow; +use std::collections::HashMap; +use std::rc::Rc; + +use clvmr::allocator::Allocator; + +use crate::classic::clvm_tools::stages::stage_0::TRunProgram; + +use crate::compiler::comptypes::{ + BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, +}; +use crate::compiler::optimize::{ + deinline_opt, fe_opt, null_optimization, optimize_expr, run_optimizer, CompileContextWrapper, + Optimization, +}; +use crate::compiler::sexp::SExp; +use crate::compiler::StartOfCodegenOptimization; + +/// Captures the existing strategy set for cl22 and below. +#[derive(Default, Clone)] +pub struct ExistingStrategy {} + +impl ExistingStrategy { + pub fn new() -> Self { + ExistingStrategy {} + } +} + +impl Optimization for ExistingStrategy { + fn frontend_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + p0: CompileForm, + ) -> Result { + // Not yet turned on for >22 + if opts.frontend_opt() && !(opts.dialect().stepping.map(|d| d > 22).unwrap_or(false)) { + // Front end optimization + fe_opt(allocator, runner, opts.clone(), p0) + } else { + Ok(p0) + } + } + + fn post_desugar_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + cf: CompileForm, + ) -> Result { + if opts.frontend_opt() && opts.dialect().stepping.map(|s| s > 22).unwrap_or(false) { + let mut symbols = HashMap::new(); + let mut wrapper = + CompileContextWrapper::new(allocator, runner, &mut symbols, self.duplicate()); + deinline_opt(&mut wrapper.context, opts.clone(), cf) + } else { + Ok(cf) + } + } + + fn start_of_codegen_optimization( + &mut self, + _allocator: &mut Allocator, + _runner: Rc, + _opts: Rc, + to_optimize: StartOfCodegenOptimization, + ) -> Result { + Ok(to_optimize) + } + + fn macro_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + code: Rc, + ) -> Result, CompileErr> { + if opts.optimize() { + run_optimizer(allocator, runner, code) + } else { + Ok(code) + } + } + + fn defun_body_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + codegen: &PrimaryCodegen, + defun: &DefunData, + ) -> Result, CompileErr> { + let res = if opts.optimize() { + // Run optimizer on frontend style forms. + optimize_expr( + allocator, + opts.clone(), + runner.clone(), + codegen, + defun.body.clone(), + ) + .map(|x| x.1) + .unwrap_or_else(|| defun.body.clone()) + } else { + defun.body.clone() + }; + Ok(res) + } + + fn post_codegen_function_optimize( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + helper: Option<&HelperForm>, + code: Rc, + ) -> Result, CompileErr> { + if opts.optimize() && helper.is_some() { + run_optimizer(allocator, runner, code) + } else { + Ok(code) + } + } + + fn pre_final_codegen_optimize( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + codegen: &PrimaryCodegen, + ) -> Result, CompileErr> { + let res = if opts.optimize() { + optimize_expr( + allocator, + opts.clone(), + runner, + codegen, + codegen.final_expr.clone(), + ) + .map(|x| x.1) + .unwrap_or_else(|| codegen.final_expr.clone()) + } else { + codegen.final_expr.clone() + }; + + Ok(res) + } + + fn post_codegen_output_optimize( + &mut self, + opts: Rc, + generated: SExp, + ) -> Result { + if opts.frontend_opt() && opts.dialect().stepping.map(|s| s > 22).unwrap_or(false) { + let (did_work, optimized) = null_optimization(Rc::new(generated.clone()), false); + if did_work { + let o_borrowed: &SExp = optimized.borrow(); + return Ok(o_borrowed.clone()); + } + } + + Ok(generated) + } + + fn duplicate(&self) -> Box { + Box::new(self.clone()) + } +} diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index ca47292e5..b4d966f23 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -394,15 +394,10 @@ fn rename_in_helperform( })), HelperForm::Defun(inline, defun) => Ok(HelperForm::Defun( *inline, - DefunData { - loc: defun.loc.clone(), - kw: defun.kw.clone(), - nl: defun.nl.clone(), - name: defun.name.to_vec(), - orig_args: defun.orig_args.clone(), - args: defun.args.clone(), + Box::new(DefunData { body: Rc::new(rename_in_bodyform(namemap, defun.body.clone())?), - }, + ..*defun.clone() + }), )), } } @@ -450,18 +445,14 @@ fn rename_args_helperform(h: &HelperForm) -> Result { let local_renamed_body = rename_args_bodyform(defun.body.borrow())?; Ok(HelperForm::Defun( *inline, - DefunData { - loc: defun.loc.clone(), - nl: defun.nl.clone(), - kw: defun.kw.clone(), - name: defun.name.clone(), - orig_args: defun.orig_args.clone(), + Box::new(DefunData { args: local_renamed_arg, body: Rc::new(rename_in_bodyform( &local_namemap, Rc::new(local_renamed_body), )?), - }, + ..*defun.clone() + }), )) } } From 9751ec17e08ee0e68e7ef8f6f654c2bacf94723c Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 20 Sep 2023 02:58:34 -0700 Subject: [PATCH 152/196] tests passing again --- src/compiler/evaluate.rs | 7 ++++--- src/tests/classic/run.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 67bb0b0d9..2c8758c84 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -743,7 +743,7 @@ impl<'info> Evaluator { fn invoke_primitive( &self, allocator: &mut Allocator, - visited: &mut VisitedMarker<'info, VisitedInfo>, + visited_: &'_ mut VisitedMarker<'info, VisitedInfo>, call: &CallSpec, prog_args: Rc, arguments_to_convert: &[Rc], @@ -752,6 +752,7 @@ impl<'info> Evaluator { ) -> Result, CompileErr> { let mut all_primitive = true; let mut target_vec: Vec> = call.args.to_owned(); + let mut visited = VisitedMarker::again(call.loc.clone(), visited_)?; if call.name == "@".as_bytes() { // Synthesize the environment for this function @@ -791,7 +792,7 @@ impl<'info> Evaluator { let i = arguments_to_convert.len() - i_reverse - 1; let shrunk = self.shrink_bodyform_visited( allocator, - visited, + &mut visited, prog_args.clone(), env, arguments_to_convert[i].clone(), @@ -832,7 +833,7 @@ impl<'info> Evaluator { // Since this is a primitive, there's no tail transform. let reformed = BodyForm::Call(call.loc.clone(), target_vec.clone(), call.tail.clone()); - self.chase_apply(allocator, visited, Rc::new(reformed)) + self.chase_apply(allocator, &mut visited, Rc::new(reformed)) } }) .unwrap_or_else(|| { diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 42b66546c..b18bc4c16 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -530,7 +530,7 @@ fn test_treehash_constant_embedded_modern_loop() { .trim() .to_string(); eprintln!("{result_text}"); - assert!(result_text.starts_with("*command*")); + // It's really only needed to check that we get a valid error return. assert!(result_text.contains("stack limit exceeded")); } From c838bf9e882e398b1caf28b42da8931de31da396 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 08:34:53 -0700 Subject: [PATCH 153/196] WIP moving on to deploying the trait methods --- src/compiler/codegen.rs | 8 ++- src/compiler/compiler.rs | 6 ++- src/compiler/evaluate.rs | 8 ++- src/compiler/inline.rs | 13 +++-- src/compiler/mod.rs | 103 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+), 9 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 886ca7ea8..7b34918a2 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -523,8 +523,12 @@ pub fn do_mod_codegen( let mut throwaway_symbols = HashMap::new(); let runner = context.runner(); let optimizer = get_optimizer(&program.loc, opts.clone())?; - let mut context_wrapper = - CompileContextWrapper::new(context.allocator(), runner.clone(), &mut throwaway_symbols, optimizer); + let mut context_wrapper = CompileContextWrapper::new( + context.allocator(), + runner.clone(), + &mut throwaway_symbols, + optimizer, + ); let code = codegen(&mut context_wrapper.context, without_env, program)?; Ok(CompiledCode( program.loc.clone(), diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 40725458b..b762c4c15 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -196,7 +196,8 @@ pub fn compile_file( let loc = Srcloc::start(&opts.filename()); let optimizer = get_optimizer(&loc, opts.clone())?; let pre_forms = parse_sexp(loc, content.bytes())?; - let mut context_wrapper = CompileContextWrapper::new(allocator, runner, symbol_table, optimizer); + let mut context_wrapper = + CompileContextWrapper::new(allocator, runner, symbol_table, optimizer); compile_pre_forms(&mut context_wrapper.context, opts, &pre_forms) } @@ -351,7 +352,8 @@ impl CompilerOpts for DefaultCompilerOpts { ) -> Result { let me = Rc::new(self.clone()); let optimizer = get_optimizer(&sexp.loc(), me.clone())?; - let mut context_wrapper = CompileContextWrapper::new(allocator, runner, symbol_table, optimizer); + let mut context_wrapper = + CompileContextWrapper::new(allocator, runner, symbol_table, optimizer); compile_pre_forms(&mut context_wrapper.context, me, &[sexp]) } } diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 2c8758c84..03dd492b6 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -1231,8 +1231,12 @@ impl<'info> Evaluator { // A mod form yields the compiled code. let mut symbols = HashMap::new(); let optimizer = get_optimizer(l, self.opts.clone())?; - let mut context_wrapper = - CompileContextWrapper::new(allocator, self.runner.clone(), &mut symbols, optimizer); + let mut context_wrapper = CompileContextWrapper::new( + allocator, + self.runner.clone(), + &mut symbols, + optimizer, + ); let code = codegen(&mut context_wrapper.context, self.opts.clone(), program)?; Ok(Rc::new(BodyForm::Quoted(code))) } diff --git a/src/compiler/inline.rs b/src/compiler/inline.rs index c60a6e511..92900ddff 100644 --- a/src/compiler/inline.rs +++ b/src/compiler/inline.rs @@ -1,6 +1,6 @@ use num_bigint::ToBigInt; use std::borrow::Borrow; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::rc::Rc; use crate::classic::clvm::__type_compatibility__::bi_one; @@ -14,7 +14,7 @@ use crate::compiler::comptypes::{ }; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; -use crate::compiler::BasicCompileContext; +use crate::compiler::{BasicCompileContext, CompileContextWrapper}; use crate::util::Number; @@ -491,5 +491,12 @@ pub fn replace_in_inline( callsite, inline.body.clone(), ) - .and_then(|x| generate_expr_code(context, opts, compiler, x)) + .and_then(|x| { + let mut symbols = HashMap::new(); + let runner = context.runner(); + let optimizer = context.optimizer.duplicate(); + let mut context_wrapper = + CompileContextWrapper::new(context.allocator(), runner, &mut symbols, optimizer); + generate_expr_code(&mut context_wrapper.context, opts, compiler, x) + }) } diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index ddd2ed015..17b96201c 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -76,6 +76,109 @@ impl BasicCompileContext { &mut self.symbols } + /// Called after frontend parsing and preprocessing when we have a complete + /// picture of the user's intended semantics. + fn frontend_optimization( + &mut self, + opts: Rc, + cf: CompileForm, + ) -> Result { + let runner = self.runner.clone(); + self.optimizer + .frontend_optimization(&mut self.allocator, runner, opts, cf) + } + + fn post_desugar_optimization( + &mut self, + opts: Rc, + cf: CompileForm, + ) -> Result { + let runner = self.runner.clone(); + self.optimizer + .post_desugar_optimization(&mut self.allocator, runner, opts, cf) + } + + /// Shrink the program prior to generating the final environment map and + /// doing other codegen tasks. This also serves as a tree-shaking pass. + fn start_of_codegen_optimization( + &mut self, + opts: Rc, + to_optimize: StartOfCodegenOptimization, + ) -> Result { + let runner = self.runner.clone(); + self.optimizer + .start_of_codegen_optimization(&mut self.allocator, runner, opts, to_optimize) + } + + /// Note: must take measures to ensure that the symbols are changed along + /// with any code that's changed. It's likely better to do optimizations + /// at other stages, such as post_codegen_function_optimize. + fn post_codegen_output_optimize( + &mut self, + opts: Rc, + generated: SExp, + ) -> Result { + self.optimizer.post_codegen_output_optimize(opts, generated) + } + + /// Called when a full macro program optimization is used. + fn macro_optimization( + &mut self, + opts: Rc, + code: Rc, + ) -> Result, CompileErr> { + self.optimizer + .macro_optimization(&mut self.allocator, self.runner.clone(), opts, code) + } + + /// Called to transform a defun before generating code from it. + /// Returns a new bodyform. + fn pre_codegen_function_optimize( + &mut self, + opts: Rc, + codegen: &PrimaryCodegen, + defun: &DefunData, + ) -> Result, CompileErr> { + self.optimizer.defun_body_optimization( + &mut self.allocator, + self.runner.clone(), + opts, + codegen, + defun, + ) + } + + /// Called to transform the function body after code generation. + fn post_codegen_function_optimize( + &mut self, + opts: Rc, + helper: Option<&HelperForm>, + code: Rc, + ) -> Result, CompileErr> { + self.optimizer.post_codegen_function_optimize( + &mut self.allocator, + self.runner.clone(), + opts, + helper, + code, + ) + } + + /// Call in final_codegen to get the final main bodyform to generate + /// code from. + fn pre_final_codegen_optimize( + &mut self, + opts: Rc, + codegen: &PrimaryCodegen, + ) -> Result, CompileErr> { + self.optimizer.pre_final_codegen_optimize( + &mut self.allocator, + self.runner.clone(), + opts, + codegen, + ) + } + /// Given allocator, runner and symbols, move the mutable objects into this /// BasicCompileContext so it can own them and pass a single mutable /// reference to itself down the stack. This allows these objects to be From de7a6168c30f268ed52fa8504ad859a7b609bdfc Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 10:44:03 -0700 Subject: [PATCH 154/196] Route in the first actual call --- src/compiler/codegen.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index bb50427b3..44109c8b2 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -775,21 +775,7 @@ fn codegen_( defun.args.clone(), ))); - let runner = context.runner(); - let opt = if opts.optimize() { - // Run optimizer on frontend style forms. - optimize_expr( - context.allocator(), - opts.clone(), - runner, - compiler, - defun.body.clone(), - ) - .map(|x| x.1) - .unwrap_or_else(|| defun.body.clone()) - } else { - defun.body.clone() - }; + let opt = context.pre_codegen_function_optimize(opts.clone(), compiler, defun)?; let tocompile = SExp::Cons( defun.loc.clone(), From 53620822379825d0a86bc136a364fec1803f9da1 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 10:55:35 -0700 Subject: [PATCH 155/196] final codegen --- src/compiler/codegen.rs | 62 +++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 44109c8b2..54e8a55af 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -9,7 +9,7 @@ use num_bigint::ToBigInt; use crate::classic::clvm::__type_compatibility__::bi_one; use crate::compiler::clvm::run; -use crate::compiler::compiler::{is_at_capture, run_optimizer}; +use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ fold_m, join_vecs_to_string, list_to_cons, Binding, BindingPattern, BodyForm, CallSpec, Callable, CompileErr, CompileForm, CompiledCode, CompilerOpts, ConstantKind, DefunCall, @@ -21,7 +21,7 @@ use crate::compiler::evaluate::{Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::frontend::{compile_bodyform, make_provides_set}; use crate::compiler::gensym::gensym; use crate::compiler::inline::{replace_in_inline, synthesize_args}; -use crate::compiler::optimize::{get_optimizer, optimize_expr}; +use crate::compiler::optimize::optimize_expr; use crate::compiler::lambda::lambda_codegen; use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; @@ -610,7 +610,7 @@ pub fn do_mod_codegen( let without_env = opts.set_start_env(None).set_in_defun(false); let mut throwaway_symbols = HashMap::new(); let runner = context.runner(); - let optimizer = get_optimizer(&program.loc, opts.clone())?; + let optimizer = context.optimizer.duplicate(); let mut context_wrapper = CompileContextWrapper::new( context.allocator(), runner.clone(), @@ -801,11 +801,7 @@ fn codegen_( &mut unused_symbol_table, ) .and_then(|code| { - if opts.optimize() { - run_optimizer(context.allocator(), runner, Rc::new(code)) - } else { - Ok(Rc::new(code)) - } + context.post_codegen_function_optimize(opts.clone(), Some(h), Rc::new(code)) }) .and_then(|code| { fail_if_present(defun.loc.clone(), &compiler.inlines, &defun.name, code) @@ -1382,21 +1378,17 @@ fn start_codegen( .set_frontend_opt(false); let runner = context.runner(); - updated_opts - .compile_program( - context.allocator(), - runner.clone(), - macro_program, - &mut HashMap::new(), - ) - .and_then(|code| { - if opts.optimize() { - run_optimizer(context.allocator(), runner, Rc::new(code)) - } else { - Ok(Rc::new(code)) - } - }) - .map(|code| code_generator.add_macro(&mac.name, code))? + let code = updated_opts.compile_program( + context.allocator(), + runner.clone(), + macro_program, + &mut HashMap::new(), + )?; + + let optimized_code = + context.macro_optimization(opts.clone(), Rc::new(code.clone()))?; + + code_generator.add_macro(&mac.name, optimized_code) } _ => code_generator, }; @@ -1434,25 +1426,15 @@ fn final_codegen( opts: Rc, compiler: &PrimaryCodegen, ) -> Result { - let runner = context.runner(); - let opt_final_expr = if opts.optimize() { - optimize_expr( - context.allocator(), - opts.clone(), - runner, - compiler, - compiler.final_expr.clone(), - ) - .map(|x| x.1) - .unwrap_or_else(|| compiler.final_expr.clone()) - } else { - compiler.final_expr.clone() - }; + let opt_final_expr = context.pre_final_codegen_optimize(opts.clone(), compiler)?; - generate_expr_code(context, opts, compiler, opt_final_expr).map(|code| { + let optimizer_opts = opts.clone(); + generate_expr_code(context, opts, compiler, opt_final_expr).and_then(|code| { let mut final_comp = compiler.clone(); - final_comp.final_code = Some(CompiledCode(code.0, code.1)); - final_comp + let optimized_code = + context.post_codegen_function_optimize(optimizer_opts.clone(), None, code.1.clone())?; + final_comp.final_code = Some(CompiledCode(code.0, optimized_code)); + Ok(final_comp) }) } From a46c50a584fd7c173d94001d0253bf539dd202aa Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 11:24:07 -0700 Subject: [PATCH 156/196] clvmc, more diffs elsewhere --- src/classic/clvm_tools/clvmc.rs | 36 ++++++++- src/classic/clvm_tools/cmds.rs | 3 +- src/compiler/compiler.rs | 138 +++++++++----------------------- 3 files changed, 71 insertions(+), 106 deletions(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index b4892f1b8..d206809af 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -21,9 +21,10 @@ use crate::classic::platform::distutils::dep_util::newer; use crate::compiler::clvm::convert_to_clvm_rs; use crate::compiler::compiler::compile_file; -use crate::compiler::compiler::{run_optimizer, DefaultCompilerOpts}; +use crate::compiler::compiler::DefaultCompilerOpts; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::dialect::detect_modern; +use crate::compiler::optimize::run_optimizer; use crate::compiler::runtypes::RunFailure; pub fn write_sym_output( @@ -38,8 +39,9 @@ pub fn write_sym_output( .map(|_| ()) } -pub fn compile_clvm_text( +pub fn compile_clvm_text_maybe_opt( allocator: &mut Allocator, + do_optimize: bool, opts: Rc, symbol_table: &mut HashMap, text: &str, @@ -57,10 +59,17 @@ pub fn compile_clvm_text( // to get more members that are somewhat independent. if let Some(stepping) = dialect.stepping { let runner = Rc::new(DefaultProgramRunner::new()); - let opts = opts.set_optimize(true).set_frontend_opt(stepping > 21); + let opts = opts + .set_dialect(dialect) + .set_optimize(do_optimize || stepping > 22) // Would apply to cl23 + .set_frontend_opt(stepping == 22); let unopt_res = compile_file(allocator, runner.clone(), opts, text, symbol_table); - let res = unopt_res.and_then(|x| run_optimizer(allocator, runner, Rc::new(x))); + let res = if do_optimize { + unopt_res.and_then(|x| run_optimizer(allocator, runner, Rc::new(x))) + } else { + unopt_res.map(Rc::new) + }; res.and_then(|x| { convert_to_clvm_rs(allocator, x).map_err(|r| match r { @@ -82,6 +91,25 @@ pub fn compile_clvm_text( } } +pub fn compile_clvm_text( + allocator: &mut Allocator, + opts: Rc, + symbol_table: &mut HashMap, + text: &str, + input_path: &str, + classic_with_opts: bool, +) -> Result { + compile_clvm_text_maybe_opt( + allocator, + true, + opts, + symbol_table, + text, + input_path, + classic_with_opts, + ) +} + pub fn compile_clvm_inner( allocator: &mut Allocator, opts: Rc, diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 52d953d40..96eafcb87 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -52,9 +52,10 @@ use crate::classic::platform::argparse::{ use crate::compiler::cldb::{hex_to_modern_sexp, CldbNoOverride, CldbRun, CldbRunEnv}; use crate::compiler::cldb_hierarchy::{HierarchialRunner, HierarchialStepResult, RunPurpose}; use crate::compiler::clvm::start_step; -use crate::compiler::compiler::{compile_file, run_optimizer, DefaultCompilerOpts}; +use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::debug::build_symbol_table_mut; +use crate::compiler::optimize::run_optimizer; use crate::compiler::preprocessor::gather_dependencies; use crate::compiler::prims; use crate::compiler::runtypes::RunFailure; diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index b762c4c15..7da91632a 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -93,60 +93,34 @@ pub fn create_prim_map() -> Rc, Rc>> { Rc::new(prim_map) } -fn fe_opt( +fn do_desugar(program: &CompileForm) -> Result { + // Transform let bindings, merging nested let scopes with the top namespace + let hoisted_bindings = hoist_body_let_binding(None, program.args.clone(), program.exp.clone())?; + let mut new_helpers = hoisted_bindings.0; + let expr = hoisted_bindings.1; // expr is the let-hoisted program + + // TODO: Distinguish the frontend_helpers and the hoisted_let helpers for later stages + let mut combined_helpers = program.helpers.clone(); + combined_helpers.append(&mut new_helpers); + let combined_helpers = process_helper_let_bindings(&combined_helpers)?; + + Ok(CompileForm { + helpers: combined_helpers, + exp: expr, + ..program.clone() + }) +} + +pub fn desugar_pre_forms( context: &mut BasicCompileContext, opts: Rc, - compileform: CompileForm, + pre_forms: &[Rc], ) -> Result { - let runner = context.runner(); - let evaluator = Evaluator::new(opts.clone(), runner.clone(), compileform.helpers.clone()); - let mut optimized_helpers: Vec = Vec::new(); - for h in compileform.helpers.iter() { - match h { - HelperForm::Defun(inline, defun) => { - let mut env = HashMap::new(); - build_reflex_captures(&mut env, defun.args.clone()); - let body_rc = evaluator.shrink_bodyform( - context.allocator(), - defun.args.clone(), - &env, - defun.body.clone(), - true, - Some(EVAL_STACK_LIMIT), - )?; - let new_helper = HelperForm::Defun( - *inline, - Box::new(DefunData { - orig_args: defun.orig_args.clone(), - body: body_rc.clone(), - ..*defun.clone() - }), - ); - optimized_helpers.push(new_helper); - } - obj => { - optimized_helpers.push(obj.clone()); - } - } - } - let new_evaluator = Evaluator::new(opts.clone(), runner.clone(), optimized_helpers.clone()); + let p0 = frontend(opts.clone(), pre_forms)?; - let shrunk = new_evaluator.shrink_bodyform( - context.allocator(), - Rc::new(SExp::Nil(compileform.args.loc())), - &HashMap::new(), - compileform.exp.clone(), - true, - Some(EVAL_STACK_LIMIT), - )?; + let p1 = context.frontend_optimization(opts.clone(), p0)?; - Ok(CompileForm { - loc: compileform.loc.clone(), - include_forms: compileform.include_forms.clone(), - args: compileform.args, - helpers: optimized_helpers.clone(), - exp: shrunk, - }) + do_desugar(&p1) } pub fn compile_pre_forms( @@ -155,35 +129,16 @@ pub fn compile_pre_forms( pre_forms: &[Rc], ) -> Result { // Resolve includes, convert program source to lexemes - let p0 = frontend(opts.clone(), pre_forms)?; + let p2 = desugar_pre_forms(context, opts.clone(), pre_forms)?; - let p1 = if opts.frontend_opt() { - // Front end optimization - fe_opt(context, opts.clone(), p0)? - } else { - p0 - }; - - // Transform let bindings, merging nested let scopes with the top namespace - let hoisted_bindings = hoist_body_let_binding(None, p1.args.clone(), p1.exp.clone())?; - let mut new_helpers = hoisted_bindings.0; - let expr = hoisted_bindings.1; // expr is the let-hoisted program + let p3 = context.post_desugar_optimization(opts.clone(), p2)?; - // TODO: Distinguish the frontend_helpers and the hoisted_let helpers for later stages - let mut combined_helpers = p1.helpers.clone(); - combined_helpers.append(&mut new_helpers); - let combined_helpers = process_helper_let_bindings(&combined_helpers)?; + // generate code from AST, optionally with optimization + let generated = codegen(context, opts.clone(), &p3)?; - let p2 = CompileForm { - loc: p1.loc.clone(), - include_forms: p1.include_forms.clone(), - args: p1.args, - helpers: combined_helpers, - exp: expr, - }; + let g2 = context.post_codegen_output_optimize(opts, generated)?; - // generate code from AST, optionally with optimization - codegen(context, opts, &p2) + Ok(g2) } pub fn compile_file( @@ -193,36 +148,17 @@ pub fn compile_file( content: &str, symbol_table: &mut HashMap, ) -> Result { - let loc = Srcloc::start(&opts.filename()); - let optimizer = get_optimizer(&loc, opts.clone())?; - let pre_forms = parse_sexp(loc, content.bytes())?; - let mut context_wrapper = - CompileContextWrapper::new(allocator, runner, symbol_table, optimizer); + let srcloc = Srcloc::start(&opts.filename()); + let pre_forms = parse_sexp(srcloc.clone(), content.bytes())?; + let mut context_wrapper = CompileContextWrapper::new( + allocator, + runner, + symbol_table, + get_optimizer(&srcloc, opts.clone())?, + ); compile_pre_forms(&mut context_wrapper.context, opts, &pre_forms) } -pub fn run_optimizer( - allocator: &mut Allocator, - runner: Rc, - r: Rc, -) -> Result, CompileErr> { - let to_clvm_rs = convert_to_clvm_rs(allocator, r.clone()) - .map(|x| (r.loc(), x)) - .map_err(|e| match e { - RunFailure::RunErr(l, e) => CompileErr(l, e), - RunFailure::RunExn(s, e) => CompileErr(s, format!("exception {e}\n")), - })?; - - let optimized = optimize_sexp(allocator, to_clvm_rs.1, runner) - .map_err(|e| CompileErr(to_clvm_rs.0.clone(), e.1)) - .map(|x| (to_clvm_rs.0, x))?; - - convert_from_clvm_rs(allocator, optimized.0, optimized.1).map_err(|e| match e { - RunFailure::RunErr(l, e) => CompileErr(l, e), - RunFailure::RunExn(s, e) => CompileErr(s, format!("exception {e}\n")), - }) -} - impl CompilerOpts for DefaultCompilerOpts { fn filename(&self) -> String { self.filename.clone() From aeac484ff90b1453d57f8d4de8efd9772860846f Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 11:40:47 -0700 Subject: [PATCH 157/196] All methods represented --- src/compiler/codegen.rs | 42 ++++++++++++++++++++++++++++++++++++++-- src/compiler/compiler.rs | 7 ++----- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 54e8a55af..e65632e7a 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -9,6 +9,7 @@ use num_bigint::ToBigInt; use crate::classic::clvm::__type_compatibility__::bi_one; use crate::compiler::clvm::run; +use crate::compiler::StartOfCodegenOptimization; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ fold_m, join_vecs_to_string, list_to_cons, Binding, BindingPattern, BodyForm, CallSpec, @@ -21,7 +22,6 @@ use crate::compiler::evaluate::{Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::frontend::{compile_bodyform, make_provides_set}; use crate::compiler::gensym::gensym; use crate::compiler::inline::{replace_in_inline, synthesize_args}; -use crate::compiler::optimize::optimize_expr; use crate::compiler::lambda::lambda_codegen; use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; @@ -1542,7 +1542,45 @@ pub fn codegen( opts: Rc, cmod: &CompileForm, ) -> Result { - let mut code_generator = dummy_functions(&start_codegen(context, opts.clone(), cmod.clone())?)?; + let mut start_of_codegen_optimization = StartOfCodegenOptimization { + program: cmod.clone(), + code_generator: dummy_functions(&start_codegen(context, opts.clone(), cmod.clone())?)?, + }; + + // This is a tree-shaking loop. It results in the minimum number of emitted + // helpers in the environment by taking only those still alive after each + // optimization pass. If a function is constant at all call sites, then + // then the function will be constant reduced and won't appear when we do + // the live calculation again, which can also remove the last reference to + // other helpers. + loop { + // We should not modify the environment if we're here on behalf of a + // function in a program, only the toplevel program itself. + if opts.in_defun() { + break; + } + + let newly_optimized_start = context + .start_of_codegen_optimization(opts.clone(), start_of_codegen_optimization.clone())?; + + // We got back the same program, so nothing will change anymore. + if newly_optimized_start.program.to_sexp() + == start_of_codegen_optimization.program.to_sexp() + { + break; + } + // Reset the optimization struct so we can go again. + // The maximum number of iterations should be about (N+1) * M where N is + // the number of functions and M is the largest number of parameters in + // any called function or operator. + let program = newly_optimized_start.program; + start_of_codegen_optimization = StartOfCodegenOptimization { + program: program.clone(), + code_generator: dummy_functions(&start_codegen(context, opts.clone(), program)?)?, + }; + } + + let mut code_generator = start_of_codegen_optimization.code_generator; let to_process = code_generator.to_process.clone(); diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 7da91632a..cb01d8ec5 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -9,19 +9,16 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::classic::clvm_tools::stages::stage_2::optimize::optimize_sexp; -use crate::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, sha256tree}; +use crate::compiler::clvm::sha256tree; use crate::compiler::codegen::{codegen, hoist_body_let_binding, process_helper_let_bindings}; use crate::compiler::comptypes::{ - CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, + CompileErr, CompileForm, CompilerOpts, PrimaryCodegen, }; use crate::compiler::dialect::AcceptedDialect; -use crate::compiler::evaluate::{build_reflex_captures, Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::frontend::frontend; use crate::compiler::optimize::get_optimizer; use crate::compiler::prims; -use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::{parse_sexp, SExp}; use crate::compiler::srcloc::Srcloc; use crate::compiler::{BasicCompileContext, CompileContextWrapper}; From 76d5a54b077e2d8844812d0528b98964eaf97706 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 11:41:39 -0700 Subject: [PATCH 158/196] fmt + clippy --- src/compiler/codegen.rs | 2 +- src/compiler/compiler.rs | 4 +--- src/compiler/mod.rs | 6 ++++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index e65632e7a..84a48b693 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -9,7 +9,6 @@ use num_bigint::ToBigInt; use crate::classic::clvm::__type_compatibility__::bi_one; use crate::compiler::clvm::run; -use crate::compiler::StartOfCodegenOptimization; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ fold_m, join_vecs_to_string, list_to_cons, Binding, BindingPattern, BodyForm, CallSpec, @@ -27,6 +26,7 @@ use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; +use crate::compiler::StartOfCodegenOptimization; use crate::compiler::{BasicCompileContext, CompileContextWrapper}; use crate::util::{toposort, u8_from_number, TopoSortItem}; diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index cb01d8ec5..f3c1c8273 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -12,9 +12,7 @@ use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::compiler::clvm::sha256tree; use crate::compiler::codegen::{codegen, hoist_body_let_binding, process_helper_let_bindings}; -use crate::compiler::comptypes::{ - CompileErr, CompileForm, CompilerOpts, PrimaryCodegen, -}; +use crate::compiler::comptypes::{CompileErr, CompileForm, CompilerOpts, PrimaryCodegen}; use crate::compiler::dialect::AcceptedDialect; use crate::compiler::frontend::frontend; use crate::compiler::optimize::get_optimizer; diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 1fdad64d4..270a2f82e 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -38,9 +38,11 @@ use std::mem::swap; use std::rc::Rc; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::comptypes::{BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen}; -use crate::compiler::sexp::SExp; +use crate::compiler::comptypes::{ + BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, +}; use crate::compiler::optimize::Optimization; +use crate::compiler::sexp::SExp; /// An object which represents the standard set of mutable items passed down the /// stack when compiling chialisp. From d6daf779a4e8fd1e15d74f975aa819a93cb2c99d Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 13:19:15 -0700 Subject: [PATCH 159/196] Remove cl23 specific code ... we'll put it back later --- src/compiler/optimize/mod.rs | 210 +++++------------------------------ src/tests/compiler/mod.rs | 1 + 2 files changed, 29 insertions(+), 182 deletions(-) diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index 01b6bf99d..55c7464d4 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -17,19 +17,17 @@ use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::classic::clvm_tools::stages::stage_2::optimize::optimize_sexp; use crate::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, run}; -use crate::compiler::codegen::{codegen, do_mod_codegen, get_callable}; +use crate::compiler::codegen::{codegen, get_callable}; use crate::compiler::comptypes::{ BodyForm, CallSpec, Callable, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, SyntheticType, }; -use crate::compiler::evaluate::{ - build_reflex_captures, dequote, is_i_atom, is_not_atom, Evaluator, EVAL_STACK_LIMIT, -}; +use crate::compiler::evaluate::{build_reflex_captures, Evaluator, EVAL_STACK_LIMIT}; use crate::compiler::optimize::strategy::ExistingStrategy; use crate::compiler::runtypes::RunFailure; -#[cfg(test)] -use crate::compiler::sexp::parse_sexp; use crate::compiler::sexp::SExp; +#[cfg(test)] +use crate::compiler::sexp::{enlist, parse_sexp}; use crate::compiler::srcloc::Srcloc; use crate::compiler::BasicCompileContext; use crate::compiler::CompileContextWrapper; @@ -169,17 +167,6 @@ fn is_at_form(head: Rc) -> bool { } } -fn get_primitive_quoted_value(form: Rc) -> Option> { - if let SExp::Cons(l, a, b) = form.borrow() { - let a_borrowed: &SExp = a.borrow(); - if a_borrowed == &SExp::Atom(l.clone(), vec![1]) { - return Some(b.clone()); - } - } - - None -} - // Return a score for sexp size. pub fn sexp_scale(sexp: &SExp) -> u64 { match sexp { @@ -209,51 +196,28 @@ fn test_sexp_scale_increases_with_atom_size() { ); } -fn is_not_condition(bf: &BodyForm) -> Option> { - // Checking for a primitive so no tail. - if let BodyForm::Call(_, parts, None) = bf { - if parts.len() != 2 { - return None; - } - - if is_not_atom(parts[0].to_sexp()) { - return Some(parts[1].clone()); - } - } - - None +#[test] +fn test_sexp_scale_increases_with_list_of_atoms() { + let l = Srcloc::start("*test*"); + let one_atom = Rc::new(SExp::Integer(l.clone(), bi_one())); + let target_scale = 4 + 3 * sexp_scale(one_atom.borrow()); + let list_of_atom = enlist( + l.clone(), + &[one_atom.clone(), one_atom.clone(), one_atom.clone()], + ); + assert_eq!(target_scale, sexp_scale(&list_of_atom)); } /// Changes (i (not c) a b) into (i c b a) fn condition_invert_optimize( opts: Rc, - loc: &Srcloc, - forms: &[Rc], + _loc: &Srcloc, + _forms: &[Rc], ) -> Option { if let Some(res) = opts.dialect().stepping { - // Only perform on chialisp above the appropriate stepping. - if res >= 23 { - if forms.len() != 4 { - return None; - } - - if !is_i_atom(forms[0].to_sexp()) { - return None; - } - - // We have a (not cond) - if let Some(condition) = is_not_condition(forms[1].borrow()) { - return Some(BodyForm::Call( - loc.clone(), - vec![ - forms[0].clone(), - condition, - forms[3].clone(), - forms[2].clone(), - ], - None, - )); - } + // Only perform on chialisp above stepping 23. + if res < 23 { + return None; } } @@ -265,115 +229,15 @@ fn condition_invert_optimize( /// /// The result is the constant result of invoking the function. fn constant_fun_result( - allocator: &mut Allocator, + _allocator: &mut Allocator, opts: Rc, - runner: Rc, - compiler: &PrimaryCodegen, - call_spec: &CallSpec, + _runner: Rc, + _compiler: &PrimaryCodegen, + _call_spec: &CallSpec, ) -> Option> { if let Some(res) = opts.dialect().stepping { - if res >= 23 { - let mut constant = true; - let optimized_args: Vec<(bool, Rc)> = call_spec - .args - .iter() - .skip(1) - .map(|a| { - let optimized = - optimize_expr(allocator, opts.clone(), runner.clone(), compiler, a.clone()); - constant = constant && optimized.as_ref().map(|x| x.0).unwrap_or_else(|| false); - optimized - .map(|x| (x.0, x.1)) - .unwrap_or_else(|| (false, a.clone())) - }) - .collect(); - - let optimized_tail: Option<(bool, Rc)> = call_spec.tail.as_ref().map(|t| { - let optimized = - optimize_expr(allocator, opts.clone(), runner.clone(), compiler, t.clone()); - constant = constant && optimized.as_ref().map(|x| x.0).unwrap_or_else(|| false); - optimized - .map(|x| (x.0, x.1)) - .unwrap_or_else(|| (false, t.clone())) - }); - - if !constant { - return None; - } - - let compiled_body = { - let to_compile = CompileForm { - loc: call_spec.loc.clone(), - include_forms: Vec::new(), - helpers: compiler.original_helpers.clone(), - args: Rc::new(SExp::Atom(call_spec.loc.clone(), b"__ARGS__".to_vec())), - exp: Rc::new(BodyForm::Call( - call_spec.loc.clone(), - vec![ - Rc::new(BodyForm::Value(SExp::Atom(call_spec.loc.clone(), vec![2]))), - Rc::new(BodyForm::Value(SExp::Atom( - call_spec.loc.clone(), - call_spec.name.to_vec(), - ))), - Rc::new(BodyForm::Value(SExp::Atom( - call_spec.loc.clone(), - b"__ARGS__".to_vec(), - ))), - ], - // Proper call: we're calling 'a' on behalf of our - // single capture argument. - None, - )), - }; - let optimizer = if let Ok(res) = get_optimizer(&call_spec.loc, opts.clone()) { - res - } else { - return None; - }; - - let mut symbols = HashMap::new(); - let mut wrapper = - CompileContextWrapper::new(allocator, runner.clone(), &mut symbols, optimizer); - - if let Ok(code) = codegen(&mut wrapper.context, opts.clone(), &to_compile) { - code - } else { - return None; - } - }; - - // Reified args reflect the actual ABI shape with a tail if any. - let mut reified_args = if let Some((_, t)) = optimized_tail { - if let Ok(res) = dequote(call_spec.loc.clone(), t) { - res - } else { - return None; - } - } else { - Rc::new(SExp::Nil(call_spec.loc.clone())) - }; - for (_, v) in optimized_args.iter().rev() { - let unquoted = if let Ok(res) = dequote(call_spec.loc.clone(), v.clone()) { - res - } else { - return None; - }; - reified_args = Rc::new(SExp::Cons(call_spec.loc.clone(), unquoted, reified_args)); - } - let borrowed_args: &SExp = reified_args.borrow(); - let new_body = BodyForm::Call( - call_spec.loc.clone(), - vec![ - Rc::new(BodyForm::Value(SExp::Atom(call_spec.loc.clone(), vec![2]))), - Rc::new(BodyForm::Quoted(compiled_body)), - Rc::new(BodyForm::Quoted(borrowed_args.clone())), - ], - // The constructed call is proper because we're feeding something - // we constructed above. - None, - ); - - return Some(Rc::new(new_body)); + if res < 23 { + return None; } } @@ -522,28 +386,10 @@ pub fn optimize_expr( true, Rc::new(BodyForm::Quoted(SExp::Integer(l.clone(), i.clone()))), )), - BodyForm::Mod(l, cf) => { + BodyForm::Mod(_l, _cf) => { if let Some(stepping) = opts.dialect().stepping { - if stepping >= 23 { - let mut throwaway_symbols = HashMap::new(); - if let Ok(optimizer) = get_optimizer(l, opts.clone()) { - let mut wrapper = CompileContextWrapper::new( - allocator, - runner, - &mut throwaway_symbols, - optimizer, - ); - if let Ok(compiled) = do_mod_codegen(&mut wrapper.context, opts.clone(), cf) - { - if let Some(body) = get_primitive_quoted_value(compiled.1) { - let borrowed_body: &SExp = body.borrow(); - return Some(( - true, - Rc::new(BodyForm::Quoted(borrowed_body.clone())), - )); - } - } - } + if stepping < 23 { + return None; } } diff --git a/src/tests/compiler/mod.rs b/src/tests/compiler/mod.rs index 74cb6aa23..e08bf88f2 100644 --- a/src/tests/compiler/mod.rs +++ b/src/tests/compiler/mod.rs @@ -9,6 +9,7 @@ mod cldb; mod clvm; mod compiler; mod evaluate; +mod optimizer; mod repl; mod restargs; mod runtypes; From d0d074bf8ab299dffc7335c49357c5d8eb7b226b Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 13:22:06 -0700 Subject: [PATCH 160/196] Didn't wind up adding tests in optimizer --- src/tests/compiler/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/compiler/mod.rs b/src/tests/compiler/mod.rs index e08bf88f2..74cb6aa23 100644 --- a/src/tests/compiler/mod.rs +++ b/src/tests/compiler/mod.rs @@ -9,7 +9,6 @@ mod cldb; mod clvm; mod compiler; mod evaluate; -mod optimizer; mod repl; mod restargs; mod runtypes; From 0782abc390e909ba69688c6c7b6b4de5fee097a9 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 14:33:21 -0700 Subject: [PATCH 161/196] Move in and make run_optimizer private so we can control its uses centrally --- src/classic/clvm_tools/clvmc.rs | 18 +++++++++++------- src/classic/clvm_tools/cmds.rs | 30 +++++++++++++++++++----------- src/compiler/optimize/mod.rs | 20 +++++++++++++++++++- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index d206809af..8fe7d3202 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -24,7 +24,7 @@ use crate::compiler::compiler::compile_file; use crate::compiler::compiler::DefaultCompilerOpts; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::dialect::detect_modern; -use crate::compiler::optimize::run_optimizer; +use crate::compiler::optimize::maybe_finalize_program_via_classic_optimizer; use crate::compiler::runtypes::RunFailure; pub fn write_sym_output( @@ -64,12 +64,16 @@ pub fn compile_clvm_text_maybe_opt( .set_optimize(do_optimize || stepping > 22) // Would apply to cl23 .set_frontend_opt(stepping == 22); - let unopt_res = compile_file(allocator, runner.clone(), opts, text, symbol_table); - let res = if do_optimize { - unopt_res.and_then(|x| run_optimizer(allocator, runner, Rc::new(x))) - } else { - unopt_res.map(Rc::new) - }; + let unopt_res = compile_file(allocator, runner.clone(), opts.clone(), text, symbol_table); + let res = unopt_res.and_then(|x| { + maybe_finalize_program_via_classic_optimizer( + allocator, + runner, + opts, + do_optimize, + &x, + ) + }); res.and_then(|x| { convert_to_clvm_rs(allocator, x).map_err(|r| match r { diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 96eafcb87..01d446d9a 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -55,7 +55,7 @@ use crate::compiler::clvm::start_step; use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::debug::build_symbol_table_mut; -use crate::compiler::optimize::run_optimizer; +use crate::compiler::optimize::maybe_finalize_program_via_classic_optimizer; use crate::compiler::preprocessor::gather_dependencies; use crate::compiler::prims; use crate::compiler::runtypes::RunFailure; @@ -630,11 +630,15 @@ pub fn cldb(args: &[String]) { &input_program, &mut use_symbol_table, ); - if do_optimize { - unopt_res.and_then(|x| run_optimizer(&mut allocator, runner.clone(), Rc::new(x))) - } else { - unopt_res.map(Rc::new) - } + unopt_res.and_then(|x| { + maybe_finalize_program_via_classic_optimizer( + &mut allocator, + runner.clone(), + opts, + false, + &x + ) + }) } }; @@ -1258,11 +1262,15 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul &input_program, &mut symbol_table, ); - let res = if do_optimize { - unopt_res.and_then(|x| run_optimizer(&mut allocator, runner, Rc::new(x))) - } else { - unopt_res.map(Rc::new) - }; + let res = unopt_res.and_then(|x| { + maybe_finalize_program_via_classic_optimizer( + &mut allocator, + runner, + opts, + do_optimize, + &x, + ) + }); match res { Ok(r) => { diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index 55c7464d4..a4714ce8c 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -568,7 +568,7 @@ fn fe_opt( }) } -pub fn run_optimizer( +fn run_optimizer( allocator: &mut Allocator, runner: Rc, r: Rc, @@ -611,3 +611,21 @@ pub fn get_optimizer( Ok(Box::new(ExistingStrategy::new())) } + +/// This small interface takes care of various scenarios that have existed +/// regarding mixing modern chialisp output with classic's optimizer. +pub fn maybe_finalize_program_via_classic_optimizer( + allocator: &mut Allocator, + runner: Rc, + _opts: Rc, // Currently unused but I want this interface + // to consider opts in the future when required. + opt_flag: bool, // Command line flag and other features control this in oldest + // versions + unopt_res: &SExp +) -> Result, CompileErr> { + if opt_flag { + run_optimizer(allocator, runner, Rc::new(unopt_res.clone())) + } else { + Ok(Rc::new(unopt_res.clone())) + } +} From bba84abec08be5cab82f74cccc60728ae84e86b6 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 21 Sep 2023 14:34:55 -0700 Subject: [PATCH 162/196] fmt --- src/classic/clvm_tools/clvmc.rs | 8 +------- src/classic/clvm_tools/cmds.rs | 2 +- src/compiler/optimize/mod.rs | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index 8fe7d3202..1ef267e4a 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -66,13 +66,7 @@ pub fn compile_clvm_text_maybe_opt( let unopt_res = compile_file(allocator, runner.clone(), opts.clone(), text, symbol_table); let res = unopt_res.and_then(|x| { - maybe_finalize_program_via_classic_optimizer( - allocator, - runner, - opts, - do_optimize, - &x, - ) + maybe_finalize_program_via_classic_optimizer(allocator, runner, opts, do_optimize, &x) }); res.and_then(|x| { diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 01d446d9a..7e607c4be 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -636,7 +636,7 @@ pub fn cldb(args: &[String]) { runner.clone(), opts, false, - &x + &x, ) }) } diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index a4714ce8c..0b7c666d7 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -621,7 +621,7 @@ pub fn maybe_finalize_program_via_classic_optimizer( // to consider opts in the future when required. opt_flag: bool, // Command line flag and other features control this in oldest // versions - unopt_res: &SExp + unopt_res: &SExp, ) -> Result, CompileErr> { if opt_flag { run_optimizer(allocator, runner, Rc::new(unopt_res.clone())) From df48f917d33f736cb3113bd6fa087fba893f4d48 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 26 Sep 2023 10:20:42 -0700 Subject: [PATCH 163/196] Remove spam --- src/compiler/rename.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 09c3e85d5..7e997bae4 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -215,7 +215,6 @@ fn rename_in_bodyform( ..*letdata.clone() }), ); - eprintln!("rename {}", res.to_sexp()); Ok(res) } From bec14df91654ed14df81ea9e8edab052ded3c952 Mon Sep 17 00:00:00 2001 From: Adam Kelly <338792+aqk@users.noreply.github.com> Date: Tue, 26 Sep 2023 12:29:59 -0700 Subject: [PATCH 164/196] Release 0.1.36 --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- wasm/Cargo.toml | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e50a9fa5b..a1b58b09b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,3 +30,7 @@ Skipped - &rest arguments. - new bls and sec256 operators. +## 0.1.36 + +- modern lambda added +- updated some internal data strucutres and call interfaces to support env variable renaming at during closure generation / lambda capture, or any step during transformation. diff --git a/Cargo.toml b/Cargo.toml index 43ad94367..6172b9058 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clvm_tools_rs" -version = "0.1.35" +version = "0.1.36" edition = "2018" authors = ["Art Yerkes "] description = "tools for working with chialisp language; compiler, repl, python and wasm bindings" diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index fda4860f0..b37b03e44 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clvm_tools_wasm" -version = "0.1.35" +version = "0.1.36" edition = "2018" authors = ["Art Yerkes "] description = "tools for working with chialisp language; compiler, repl, python and wasm bindings" @@ -23,4 +23,4 @@ wasm-bindgen = "=0.2.83" wasm-bindgen-test = "=0.3.25" js-sys = "0.3.60" num-bigint = "0.4.0" -num-traits = "0.2.15" \ No newline at end of file +num-traits = "0.2.15" From 67abadd746097ad62a4ba1472322bd46a23d6c6d Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 26 Sep 2023 12:59:02 -0700 Subject: [PATCH 165/196] fmt + clippy --- src/compiler/evaluate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 77f2ed9d9..195d28b47 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -9,7 +9,7 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::classic::clvm_tools::stages::stage_0::TRunProgram; -use crate::compiler::clvm::{run, PrimOverride, truthy}; +use crate::compiler::clvm::{run, truthy, PrimOverride}; use crate::compiler::codegen::{codegen, hoist_assign_form}; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ From 38320d1513bea487c5e8b13e9f109d41f14f976b Mon Sep 17 00:00:00 2001 From: Adam Kelly <338792+aqk@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:01:01 -0700 Subject: [PATCH 166/196] Update lock files --- Cargo.lock | 2 +- wasm/Cargo.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2afc51d86..e24af67df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clvm_tools_rs" -version = "0.1.35" +version = "0.1.36" dependencies = [ "binascii", "bls12_381", diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 23466a11e..63de4da73 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clvm_tools_rs" -version = "0.1.35" +version = "0.1.36" dependencies = [ "binascii", "bls12_381", @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "clvm_tools_wasm" -version = "0.1.35" +version = "0.1.36" dependencies = [ "clvm_tools_rs", "clvmr", @@ -161,9 +161,9 @@ dependencies = [ [[package]] name = "clvmr" -version = "0.2.7" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2890f01537f1be43d2767ae71bbba0d0b3543dbb1ee892092d0ed4d913227fc" +checksum = "9cd344b6dc76235f446025fe9ebe54aa6131e2e59acb49e16be48a3bb3492491" dependencies = [ "bls12_381", "getrandom", From 54003dcc8400779fdd275cf27a4dc3cc6c11c086 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 26 Sep 2023 18:34:58 -0700 Subject: [PATCH 167/196] Use outputs of check_secrets step --- .github/workflows/npm-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 691fdff94..46a2d9fe6 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -78,7 +78,7 @@ jobs: SECRET: "${{ secrets.NPM_TOKEN }}" - name: Publish wasm - if: env.FULL_RELEASE == 'true' && steps.check_secrets.HAS_SECRET + if: env.FULL_RELEASE == 'true' && steps.check_secrets.outputs.HAS_SECRET env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} working-directory: ${{ github.workspace }}/wasm/pkg From 6462094b9ce0967b2bb8d599834b03362d81a359 Mon Sep 17 00:00:00 2001 From: Starttoaster Date: Wed, 27 Sep 2023 11:56:05 -0700 Subject: [PATCH 168/196] Add a publish job for clvm wheels --- .github/workflows/build-test.yml | 53 ++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 409609482..097bf1d5f 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -229,30 +229,46 @@ jobs: name: wheels path: ./target/wheels/ - - name: Test for secrets access - id: check_secrets - shell: bash + - name: Build alpine wheel via docker + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') run: | - unset HAS_AWS_SECRET + cd resources/alpine && docker build -t clvm-tools-rs-alpine . + docker run -v ${GITHUB_WORKSPACE}:/root/clvm_tools_rs -t clvm-tools-rs-alpine sh /root/build-alpine.sh - if [ -n "$AWS_SECRET" ]; then HAS_AWS_SECRET='true' ; fi - echo HAS_AWS_SECRET=${HAS_AWS_SECRET} >>$GITHUB_OUTPUT - env: - AWS_SECRET: "${{ secrets.CHIA_AWS_ACCOUNT_ID }}" + upload: + name: Upload to PyPI + runs-on: ubuntu-latest + needs: build_wheels + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Set Env uses: Chia-Network/actions/setjobenv@main env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: publish (PyPi) + - name: Install python + uses: Chia-Network/actions/setup-python@main + with: + python-version: 3.9 + + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: wheels + path: ./target/wheels/ + + - name: Publish distribution to PyPI if: env.RELEASE == 'true' uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: target/wheels/ skip-existing: true - - name: publish (Test PyPi) + - name: Publish distribution to Test PyPI if: env.PRE_RELEASE == 'true' uses: pypa/gh-action-pypi-publish@release/v1 with: @@ -260,6 +276,17 @@ jobs: packages-dir: target/wheels/ skip-existing: true + - name: Test for secrets access + id: check_secrets + shell: bash + run: | + unset HAS_AWS_SECRET + + if [ -n "$AWS_SECRET" ]; then HAS_AWS_SECRET='true' ; fi + echo HAS_AWS_SECRET=${HAS_AWS_SECRET} >>$GITHUB_OUTPUT + env: + AWS_SECRET: "${{ secrets.CHIA_AWS_ACCOUNT_ID }}" + - name: Configure AWS credentials if: steps.check_secrets.outputs.HAS_AWS_SECRET uses: aws-actions/configure-aws-credentials@v2 @@ -278,12 +305,6 @@ jobs: aws --no-progress s3 cp "$file" "s3://download.chia.net/simple-dev/clvm-tools-rs/$filename" done <<< "$FILES" - - name: Build alpine wheel via docker - if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') - run: | - cd resources/alpine && docker build -t clvm-tools-rs-alpine . - docker run -v ${GITHUB_WORKSPACE}:/root/clvm_tools_rs -t clvm-tools-rs-alpine sh /root/build-alpine.sh - fmt: runs-on: ubuntu-20.04 name: cargo fmt From 609c0a086d1fd6ba99f65dbaff65cbf9edb6f5b6 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 27 Sep 2023 12:01:57 -0700 Subject: [PATCH 169/196] fmt --- src/compiler/compiler.rs | 12 +--- src/compiler/frontend.rs | 5 +- src/compiler/preprocessor/macros.rs | 99 ++++++++--------------------- src/compiler/preprocessor/mod.rs | 6 +- 4 files changed, 33 insertions(+), 89 deletions(-) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 7f458d078..e831fcfca 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -175,9 +175,7 @@ pub fn compile_from_compileform( p0: CompileForm, symbol_table: &mut HashMap, ) -> Result { - let mut wrapper = CompileContextWrapper::new( - allocator, runner, symbol_table - ); + let mut wrapper = CompileContextWrapper::new(allocator, runner, symbol_table); let p1 = if opts.frontend_opt() { // Front end optimization fe_opt(&mut wrapper.context, opts.clone(), p0)? @@ -217,13 +215,7 @@ pub fn compile_pre_forms( // Resolve includes, convert program source to lexemes let p0 = frontend(opts.clone(), pre_forms)?; - compile_from_compileform( - allocator, - runner, - opts, - p0, - symbol_table - ) + compile_from_compileform(allocator, runner, opts, p0, symbol_table) } pub fn compile_file( diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index bcd91247e..16ba840bd 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -255,10 +255,7 @@ fn make_let_bindings( opts: Rc, body: Rc, ) -> Result>, CompileErr> { - let err = Err(CompileErr( - body.loc(), - format!("Bad binding tail {body:?}") - )); + let err = Err(CompileErr(body.loc(), format!("Bad binding tail {body:?}"))); let do_atomize = if opts.dialect().strict { |a: &SExp| -> SExp { a.atomize() } } else { diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 859d8c79b..e485181de 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -19,7 +19,7 @@ fn match_quoted_string(body: Rc) -> Result)>, Comp let is_string = match body.borrow() { SExp::QuotedString(_, b'x', _) => None, SExp::QuotedString(al, _, an) => Some((al.clone(), an.clone())), - _ => None + _ => None, }; if let Some((loc, s)) = is_string { @@ -60,7 +60,7 @@ fn match_number(body: Rc) -> Result, CompileErr> { SExp::Nil(il) => { return Ok(Some(MatchedNumber::MatchedInt(il.clone(), bi_zero()))); } - _ => { } + _ => {} } Err(CompileErr(body.loc(), "number required".to_string())) @@ -94,11 +94,7 @@ pub trait ExtensionFunction { } fn required_args(&self) -> Option; #[allow(clippy::too_many_arguments)] - fn try_eval( - &self, - loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr>; + fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr>; } struct StringQ {} @@ -114,11 +110,7 @@ impl ExtensionFunction for StringQ { Some(1) } - fn try_eval( - &self, - loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let res = match match_quoted_string(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), _ => SExp::Nil(loc.clone()), @@ -141,11 +133,7 @@ impl ExtensionFunction for NumberQ { Some(1) } - fn try_eval( - &self, - loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let res = match match_number(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), _ => SExp::Nil(loc.clone()), @@ -168,11 +156,7 @@ impl ExtensionFunction for SymbolQ { Some(1) } - fn try_eval( - &self, - loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let res = match match_atom(args[0].clone()) { Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), _ => SExp::Nil(loc.clone()), @@ -195,15 +179,9 @@ impl ExtensionFunction for SymbolToString { Some(1) } - fn try_eval( - &self, - _loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { if let Some((loc, value)) = match_atom(args[0].clone())? { - Ok(Rc::new(SExp::QuotedString( - loc, b'\"', value, - ))) + Ok(Rc::new(SExp::QuotedString(loc, b'\"', value))) } else { Err(CompileErr(args[0].loc(), "Not a symbol".to_string())) } @@ -223,11 +201,7 @@ impl ExtensionFunction for StringToSymbol { Some(1) } - fn try_eval( - &self, - _loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { Ok(Rc::new(SExp::Atom(loc, value))) } else { @@ -249,11 +223,7 @@ impl ExtensionFunction for StringAppend { None } - fn try_eval( - &self, - loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let mut out_vec = Vec::new(); let mut out_loc = None; for a in args.iter() { @@ -287,11 +257,7 @@ impl ExtensionFunction for NumberToString { Some(1) } - fn try_eval( - &self, - _loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let match_res = match_number(args[0].clone())?; let (use_loc, int_val) = match &match_res { Some(MatchedNumber::MatchedInt(l, i)) => (l.clone(), i.clone()), @@ -321,11 +287,7 @@ impl ExtensionFunction for StringToNumber { Some(1) } - fn try_eval( - &self, - loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Ok(cvt_bi) = decode_string(&value).parse::() { Ok(Rc::new(SExp::Integer(loc, cvt_bi))) @@ -354,18 +316,17 @@ impl ExtensionFunction for StringLength { Some(1) } - fn try_eval( - &self, - _loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { if let Some((loc, value)) = match_quoted_string(args[0].clone())? { if let Some(len_bi) = value.len().to_bigint() { return Ok(Rc::new(SExp::Integer(loc, len_bi))); } } - Err(CompileErr(args[0].loc(), "Error getting string length".to_string())) + Err(CompileErr( + args[0].loc(), + "Error getting string length".to_string(), + )) } } @@ -382,11 +343,7 @@ impl ExtensionFunction for Substring { Some(3) } - fn try_eval( - &self, - _loc: &Srcloc, - args: &[Rc], - ) -> Result, CompileErr> { + fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let start_element = usize_value(args[1].clone())?; let end_element = usize_value(args[2].clone())?; @@ -404,11 +361,7 @@ impl ExtensionFunction for Substring { .skip(start_element) .copied() .collect(); - Ok(Rc::new(SExp::QuotedString( - l.clone(), - *ch, - result_value, - ))) + Ok(Rc::new(SExp::QuotedString(l.clone(), *ch, result_value))) } _ => Err(CompileErr(args[0].loc(), "Not a string".to_string())), } @@ -468,15 +421,15 @@ impl PrimOverride for PreprocessorExtension { ) -> Result>, RunFailure> { eprintln!("running {head} {tail}"); if let SExp::Atom(hl, head_atom) = head.borrow() { - let have_args: Vec> = - if let Some(args_list) = tail.proper_list() { - args_list.into_iter().map(Rc::new).collect() - } else { - return Ok(None); - }; + let have_args: Vec> = if let Some(args_list) = tail.proper_list() { + args_list.into_iter().map(Rc::new).collect() + } else { + return Ok(None); + }; if let Some(extension) = self.extfuns.get(head_atom) { - let res = extension.try_eval(&hl, &have_args) + let res = extension + .try_eval(&hl, &have_args) .map_err(compile_to_run_err)?; eprintln!("res = {res}"); diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index bc94064a6..2474f5492 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -72,7 +72,7 @@ fn make_defmac_name(name: &[u8]) -> Vec { } fn nilize(v: Rc) -> Rc { - if let SExp::Cons(l,a,b) = v.borrow() { + if let SExp::Cons(l, a, b) = v.borrow() { let a_conv = nilize(a.clone()); let b_conv = nilize(b.clone()); if Rc::as_ptr(&a_conv) == Rc::as_ptr(&a) && Rc::as_ptr(&b_conv) == Rc::as_ptr(&b) { @@ -321,7 +321,9 @@ impl Preprocessor { args.clone(), Some(extension), None, - ).map(nilize).map_err(|e| CompileErr::from(e))?; + ) + .map(nilize) + .map_err(|e| CompileErr::from(e))?; eprintln!("macro {} {args} => {res}", decode_string(&name)); return Ok(Some(res)); From 7fb660dc634bd97c71d79492c26987fc2b5ed5cc Mon Sep 17 00:00:00 2001 From: Starttoaster Date: Wed, 27 Sep 2023 12:02:01 -0700 Subject: [PATCH 170/196] Build alpine wheel before upload step --- .github/workflows/build-test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 097bf1d5f..5be6e1752 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -223,18 +223,18 @@ jobs: rustup component add llvm-tools-preview python ./resources/coverage/run_coverage.py --require-percent 60 - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: wheels - path: ./target/wheels/ - - name: Build alpine wheel via docker if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') run: | cd resources/alpine && docker build -t clvm-tools-rs-alpine . docker run -v ${GITHUB_WORKSPACE}:/root/clvm_tools_rs -t clvm-tools-rs-alpine sh /root/build-alpine.sh + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: wheels + path: ./target/wheels/ + upload: name: Upload to PyPI runs-on: ubuntu-latest From e8aee718b324a25f42fc58a67f0bcce23ff93ed6 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 27 Sep 2023 12:06:06 -0700 Subject: [PATCH 171/196] clippy --- src/compiler/preprocessor/macros.rs | 6 +++--- src/compiler/preprocessor/mod.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index e485181de..4bf31b064 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -52,8 +52,8 @@ fn match_number(body: Rc) -> Result, CompileErr> { } SExp::Atom(al, b) => { // An atom with unprintable characters is rendered as an integer. - if !printable(&b) { - let to_integer = number_from_u8(&b); + if !printable(b) { + let to_integer = number_from_u8(b); return Ok(Some(MatchedNumber::MatchedInt(al.clone(), to_integer))); } } @@ -429,7 +429,7 @@ impl PrimOverride for PreprocessorExtension { if let Some(extension) = self.extfuns.get(head_atom) { let res = extension - .try_eval(&hl, &have_args) + .try_eval(hl, &have_args) .map_err(compile_to_run_err)?; eprintln!("res = {res}"); diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 2474f5492..558165fae 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -75,7 +75,7 @@ fn nilize(v: Rc) -> Rc { if let SExp::Cons(l, a, b) = v.borrow() { let a_conv = nilize(a.clone()); let b_conv = nilize(b.clone()); - if Rc::as_ptr(&a_conv) == Rc::as_ptr(&a) && Rc::as_ptr(&b_conv) == Rc::as_ptr(&b) { + if Rc::as_ptr(&a_conv) == Rc::as_ptr(a) && Rc::as_ptr(&b_conv) == Rc::as_ptr(b) { v.clone() } else { Rc::new(SExp::Cons(l.clone(), a_conv, b_conv)) @@ -323,7 +323,7 @@ impl Preprocessor { None, ) .map(nilize) - .map_err(|e| CompileErr::from(e))?; + .map_err(CompileErr::from)?; eprintln!("macro {} {args} => {res}", decode_string(&name)); return Ok(Some(res)); From f7154762e2b687c652d50d0d15e766526a67f07e Mon Sep 17 00:00:00 2001 From: Starttoaster Date: Wed, 27 Sep 2023 12:21:48 -0700 Subject: [PATCH 172/196] Use python 3.10 for upload stage --- .github/workflows/build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 5be6e1752..b3f9b9f7a 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -253,7 +253,7 @@ jobs: - name: Install python uses: Chia-Network/actions/setup-python@main with: - python-version: 3.9 + python-version: "3.10" - name: Download artifacts uses: actions/download-artifact@v3 From 85f521f3f7bd6f5708760305b4f8858263ed1fc0 Mon Sep 17 00:00:00 2001 From: Starttoaster Date: Wed, 27 Sep 2023 12:22:14 -0700 Subject: [PATCH 173/196] Use publish job for M1 wheels too --- .github/workflows/build-m1-wheel.yml | 47 +++++++++++++++++++++------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build-m1-wheel.yml b/.github/workflows/build-m1-wheel.yml index 5831afae7..415594207 100644 --- a/.github/workflows/build-m1-wheel.yml +++ b/.github/workflows/build-m1-wheel.yml @@ -111,22 +111,32 @@ jobs: name: wheels path: ./target/wheels - - name: Test for secrets access - id: check_secrets - shell: bash - run: | - unset HAS_AWS_SECRET - - if [ -n "$AWS_SECRET" ]; then HAS_AWS_SECRET='true' ; fi - echo HAS_AWS_SECRET=${HAS_AWS_SECRET} >>$GITHUB_OUTPUT - env: - AWS_SECRET: "${{ secrets.CHIA_AWS_ACCOUNT_ID }}" + upload: + name: Upload to PyPI + runs-on: ubuntu-latest + needs: build_wheels + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Set Env uses: Chia-Network/actions/setjobenv@main env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install python + uses: Chia-Network/actions/setup-python@main + with: + python-version: "3.10" + + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: wheels + path: ./target/wheels/ + - name: publish (PyPi) if: env.RELEASE == 'true' uses: pypa/gh-action-pypi-publish@release/v1 @@ -142,6 +152,17 @@ jobs: packages-dir: target/wheels/ skip-existing: true + - name: Test for secrets access + id: check_secrets + shell: bash + run: | + unset HAS_AWS_SECRET + + if [ -n "$AWS_SECRET" ]; then HAS_AWS_SECRET='true' ; fi + echo HAS_AWS_SECRET=${HAS_AWS_SECRET} >>$GITHUB_OUTPUT + env: + AWS_SECRET: "${{ secrets.CHIA_AWS_ACCOUNT_ID }}" + - name: Configure AWS credentials if: steps.check_secrets.outputs.HAS_AWS_SECRET uses: aws-actions/configure-aws-credentials@v2 @@ -151,9 +172,11 @@ jobs: - name: Publish Dev if: steps.check_secrets.outputs.HAS_AWS_SECRET && github.ref == 'refs/heads/dev' + shell: bash + working-directory: ./target/wheels run: | - FILES=$(find ${{ github.workspace }}/target/wheels -type f -name '*.whl') + FILES=$(find . -type f -name '*.whl') while IFS= read -r file; do filename=$(basename $file) aws --no-progress s3 cp "$file" "s3://download.chia.net/simple-dev/clvm-tools-rs/$filename" - done <<< "$FILES" + done <<< "$FILES" \ No newline at end of file From b15df3b982e4564401c822f2d9199c480f627471 Mon Sep 17 00:00:00 2001 From: Starttoaster Date: Wed, 27 Sep 2023 12:23:07 -0700 Subject: [PATCH 174/196] Add trailing newline in workflow for style --- .github/workflows/build-m1-wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-m1-wheel.yml b/.github/workflows/build-m1-wheel.yml index 415594207..a7a3c0a4e 100644 --- a/.github/workflows/build-m1-wheel.yml +++ b/.github/workflows/build-m1-wheel.yml @@ -179,4 +179,4 @@ jobs: while IFS= read -r file; do filename=$(basename $file) aws --no-progress s3 cp "$file" "s3://download.chia.net/simple-dev/clvm-tools-rs/$filename" - done <<< "$FILES" \ No newline at end of file + done <<< "$FILES" From 6ce652eb44b3ba5cad5ad232d459d7b0341f5d93 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 28 Sep 2023 13:37:10 -0700 Subject: [PATCH 175/196] Update version and lock files --- Cargo.lock | 2 +- Cargo.toml | 2 +- wasm/Cargo.lock | 4 ++-- wasm/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e24af67df..9df64be37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clvm_tools_rs" -version = "0.1.36" +version = "0.1.37" dependencies = [ "binascii", "bls12_381", diff --git a/Cargo.toml b/Cargo.toml index 6172b9058..aef8081c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clvm_tools_rs" -version = "0.1.36" +version = "0.1.37" edition = "2018" authors = ["Art Yerkes "] description = "tools for working with chialisp language; compiler, repl, python and wasm bindings" diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 63de4da73..7feb6b4c3 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clvm_tools_rs" -version = "0.1.36" +version = "0.1.37" dependencies = [ "binascii", "bls12_381", @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "clvm_tools_wasm" -version = "0.1.36" +version = "0.1.37" dependencies = [ "clvm_tools_rs", "clvmr", diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index b37b03e44..bb4a5e88a 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clvm_tools_wasm" -version = "0.1.36" +version = "0.1.37" edition = "2018" authors = ["Art Yerkes "] description = "tools for working with chialisp language; compiler, repl, python and wasm bindings" From 874862df019b88a0a69a4bd2cd3c5126486ba1b8 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 3 Oct 2023 09:53:51 -0700 Subject: [PATCH 176/196] Work on typescript type annotation (to test). Fix uncurrying slightly. --- wasm/src/api.rs | 2 +- wasm/src/objects.rs | 118 +++++++++++++----- .../content/test_cat2_program.hex | 1 + .../src/lib/tests/index.test.ts | 20 ++- 4 files changed, 108 insertions(+), 33 deletions(-) create mode 100644 wasm/tests/clvm-tools-interface/content/test_cat2_program.hex diff --git a/wasm/src/api.rs b/wasm/src/api.rs index 333057018..445391b7f 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -495,5 +495,5 @@ pub fn h(v: String) -> Result, JsValue> { #[wasm_bindgen] pub fn t(a: &JsValue, b: &JsValue) -> Result { - Program::as_pair_internal(&Program::cons_internal(&Program::to(a)?, &Program::to(b)?)?) + Program::as_pair_internal(&Program::cons_internal(&Program::to_internal(a)?, &Program::to_internal(b)?)?.into()) } diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 3e13b3421..481feac29 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -6,6 +6,7 @@ use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::rc::Rc; use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; use clvmr::Allocator; use clvm_tools_rs::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType, bi_one}; @@ -266,6 +267,40 @@ pub fn find_cached_sexp(entry: i32, content: &str) -> Result Result // Return a vector of arguments if the given SExp is the expected operator // and has the required number of arguments. -fn match_op(opcode: u8, expected_args: usize, opname: &str, program: Rc) -> Result>, JsValue> { +fn match_op(opcode: u8, mut expected_args: usize, opname: &str, program: Rc) -> Result>, JsValue> { let plist = - if let Some(plist) = program.proper_list() { + if expected_args == 0 { + if let SExp::Cons(_, a, b) = program.borrow() { + let a_borrowed: &SExp = a.borrow(); + let b_borrowed: &SExp = b.borrow(); + expected_args = 1; + vec![a_borrowed.clone(), b_borrowed.clone()] + } else { + return Err(JsValue::from_str(&format!("program was expected to be a cons, but wasn't: {program}"))); + } + } else if let Some(plist) = program.proper_list() { plist } else { // Not a list so can't be an apply. @@ -409,10 +453,13 @@ fn cache_and_accumulate_arg(array: &Array, prog: Rc) -> Result<(), JsValue Ok(()) } +fn to_iprogram(v: JsValue) -> IProgram { + JsValue::from(v).unchecked_into::() +} + #[wasm_bindgen] impl Program { - #[wasm_bindgen] - pub fn to(input: &JsValue) -> Result { + pub fn to_internal(input: &JsValue) -> Result { let loc = get_srcloc(); let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| Err(create_clvm_runner_err(format!("unable to convert to value"))))?; @@ -425,18 +472,23 @@ impl Program { } #[wasm_bindgen] - pub fn from_hex(input: &str) -> Result { + pub fn to(input: &JsValue) -> Result { + Program::to_internal(input).map(to_iprogram) + } + + #[wasm_bindgen] + pub fn from_hex(input: &str) -> Result { let new_id = get_next_id(); let obj = finish_new_object(new_id, input)?; - Program::to(&obj) + Program::to_internal(&obj).map(to_iprogram) } #[wasm_bindgen] - pub fn null() -> Result { + pub fn null() -> Result { let new_id = get_next_id(); let encoded = create_cached_sexp(new_id, Rc::new(SExp::Nil(get_srcloc())))?; - finish_new_object(new_id, &encoded) + finish_new_object(new_id, &encoded).map(to_iprogram) } #[wasm_bindgen] @@ -518,33 +570,33 @@ impl Program { } #[wasm_bindgen] - pub fn first_internal(obj: &JsValue) -> Result { + pub fn first_internal(obj: &JsValue) -> Result { let cacheval = js_cache_value_from_js(obj)?; let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; if let SExp::Cons(_, a, _) = cached.modern.borrow() { let id_a = get_next_id(); let new_cached_a = create_cached_sexp(id_a, a.clone())?; - return finish_new_object(id_a, &new_cached_a); + return finish_new_object(id_a, &new_cached_a).map(to_iprogram); } Err(JsString::from("not a cons").into()) } #[wasm_bindgen] - pub fn rest_internal(obj: &JsValue) -> Result { + pub fn rest_internal(obj: &JsValue) -> Result { let cacheval = js_cache_value_from_js(obj)?; let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; if let SExp::Cons(_, _, a) = cached.modern.borrow() { let id_a = get_next_id(); let new_cached_a = create_cached_sexp(id_a, a.clone())?; - return finish_new_object(id_a, &new_cached_a); + return finish_new_object(id_a, &new_cached_a).map(to_iprogram); } Err(JsString::from("not a cons").into()) } #[wasm_bindgen] - pub fn cons_internal(obj: &JsValue, other: &JsValue) -> Result { + pub fn cons_internal(obj: &JsValue, other: &JsValue) -> Result { let cacheval = js_cache_value_from_js(obj)?; let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; @@ -554,7 +606,7 @@ impl Program { let new_id = get_next_id(); let new_sexp = Rc::new(SExp::Cons(get_srcloc(), cached.modern.clone(), other_cache.modern.clone())); let new_cached = create_cached_sexp(new_id, new_sexp)?; - finish_new_object(new_id, &new_cached) + finish_new_object(new_id, &new_cached).map(to_iprogram) } #[wasm_bindgen] @@ -611,7 +663,7 @@ impl Program { } #[wasm_bindgen] - pub fn tuple_to_program_internal(obj: &JsValue) -> Result { + pub fn tuple_to_program_internal(obj: &JsValue) -> Result { let a = js_sys::Reflect::get( obj, &JsString::from("0"), @@ -687,7 +739,7 @@ impl Program { // Resulting in a function which places its own arguments after those // curried in in the form of a proper list. #[wasm_bindgen] - pub fn curry_internal(obj: &JsValue, args: Vec) -> Result { + pub fn curry_internal(obj: &JsValue, args: Vec) -> Result { let program_val = Program::to(obj)?; let cacheval = js_cache_value_from_js(&program_val)?; let program = find_cached_sexp(cacheval.entry, &cacheval.content)?; @@ -712,29 +764,39 @@ impl Program { let new_id = get_next_id(); let new_cached = create_cached_sexp(new_id, result)?; - finish_new_object(new_id, &new_cached) + finish_new_object(new_id, &new_cached).map(to_iprogram) } #[wasm_bindgen] - pub fn uncurry_error_internal(obj: &JsValue) -> Result { + pub fn uncurry_error_internal(obj: &JsValue) -> Result, JsValue> { let program_val = Program::to(obj)?; let cacheval = js_cache_value_from_js(&program_val)?; let program = find_cached_sexp(cacheval.entry, &cacheval.content)?; let apply_args = match_op(2, 2, "apply", program.modern.clone())?; + // Not used in code, but detects a quoted program. - let quoted_prog = match_op(1, 1, "quote", apply_args[0].clone())?; + let quoted_prog = match_op(1, 0, "quote", apply_args[0].clone())?; let retrieved_args = Array::new(); let mut cons_expr = match_op(4, 2, "cons", apply_args[1].clone())?; - cache_and_accumulate_arg(&retrieved_args, cons_expr[0].clone())?; + + let decons_and_unquote = |expr: Rc| { + if let Ok(unquoted_curry_argument) = match_op(1, 0, "quote", expr.clone()) { + unquoted_curry_argument[0].clone() + } else { + expr + } + }; + + cache_and_accumulate_arg(&retrieved_args, decons_and_unquote(cons_expr[0].clone()))?; let mut next_cons = cons_expr[1].clone(); while matches!(next_cons.borrow(), SExp::Cons(_, _, _)) { cons_expr = match_op(4, 2, "cons", next_cons)?; // Convert to the external js form and insert into cache so we can // forego conversion if still cached. - cache_and_accumulate_arg(&retrieved_args, cons_expr[0].clone())?; + cache_and_accumulate_arg(&retrieved_args, decons_and_unquote(cons_expr[0].clone()))?; // Move on to the tail that's being built. next_cons = cons_expr[1].clone(); @@ -751,21 +813,15 @@ impl Program { let new_cached_mod = create_cached_sexp(mod_id, quoted_prog[0].clone())?; let mod_js = finish_new_object(mod_id, &new_cached_mod)?; - let res = Array::new(); - res.push(&mod_js); - res.push(&retrieved_args); - Ok(res.into()) + Ok(vec![mod_js.into(), retrieved_args.unchecked_into::()]) } #[wasm_bindgen] - pub fn uncurry_internal(obj: &JsValue) -> JsValue { + pub fn uncurry_internal(obj: &JsValue) -> Result, JsValue> { if let Ok(res) = Program::uncurry_error_internal(obj) { - res + Ok(res) } else { - let res = Array::new(); - res.push(obj); - res.push(&JsValue::null()); - res.into() + Ok(vec![obj.clone().unchecked_into::(), Program::null()?]) } } } diff --git a/wasm/tests/clvm-tools-interface/content/test_cat2_program.hex b/wasm/tests/clvm-tools-interface/content/test_cat2_program.hex new file mode 100644 index 000000000..1fc0fa674 --- /dev/null +++ b/wasm/tests/clvm-tools-interface/content/test_cat2_program.hex @@ -0,0 +1 @@ +ff02ffff01ff02ffff01ff02ff5effff04ff02ffff04ffff04ff05ffff04ffff0bff2cff0580ffff04ff0bff80808080ffff04ffff02ff17ff2f80ffff04ff5fffff04ffff02ff2effff04ff02ffff04ff17ff80808080ffff04ffff0bff82027fff82057fff820b7f80ffff04ff81bfffff04ff82017fffff04ff8202ffffff04ff8205ffffff04ff820bffff80808080808080808080808080ffff04ffff01ffffffff81ca3dff46ff0233ffff3c04ff01ff0181cbffffff02ff02ffff03ff05ffff01ff02ff32ffff04ff02ffff04ff0dffff04ffff0bff22ffff0bff2cff3480ffff0bff22ffff0bff22ffff0bff2cff5c80ff0980ffff0bff22ff0bffff0bff2cff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ff0bffff01ff02ffff03ffff09ffff02ff2effff04ff02ffff04ff13ff80808080ff820b9f80ffff01ff02ff26ffff04ff02ffff04ffff02ff13ffff04ff5fffff04ff17ffff04ff2fffff04ff81bfffff04ff82017fffff04ff1bff8080808080808080ffff04ff82017fff8080808080ffff01ff088080ff0180ffff01ff02ffff03ff17ffff01ff02ffff03ffff20ff81bf80ffff0182017fffff01ff088080ff0180ffff01ff088080ff018080ff0180ffff04ffff04ff05ff2780ffff04ffff10ff0bff5780ff778080ff02ffff03ff05ffff01ff02ffff03ffff09ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff01818f80ffff01ff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ffff04ff81b9ff82017980ff808080808080ffff01ff02ff5affff04ff02ffff04ffff02ffff03ffff09ff11ff7880ffff01ff04ff78ffff04ffff02ff36ffff04ff02ffff04ff13ffff04ff29ffff04ffff0bff2cff5b80ffff04ff2bff80808080808080ff398080ffff01ff02ffff03ffff09ff11ff2480ffff01ff04ff24ffff04ffff0bff20ff2980ff398080ffff010980ff018080ff0180ffff04ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff04ffff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ff17ff808080808080ff80808080808080ff0180ffff01ff04ff80ffff04ff80ff17808080ff0180ffffff02ffff03ff05ffff01ff04ff09ffff02ff26ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff0bff22ffff0bff2cff5880ffff0bff22ffff0bff22ffff0bff2cff5c80ff0580ffff0bff22ffff02ff32ffff04ff02ffff04ff07ffff04ffff0bff2cff2c80ff8080808080ffff0bff2cff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bff2cff058080ff0180ffff04ffff04ff28ffff04ff5fff808080ffff02ff7effff04ff02ffff04ffff04ffff04ff2fff0580ffff04ff5fff82017f8080ffff04ffff02ff7affff04ff02ffff04ff0bffff04ff05ffff01ff808080808080ffff04ff17ffff04ff81bfffff04ff82017fffff04ffff0bff8204ffffff02ff36ffff04ff02ffff04ff09ffff04ff820affffff04ffff0bff2cff2d80ffff04ff15ff80808080808080ff8216ff80ffff04ff8205ffffff04ff820bffff808080808080808080808080ff02ff2affff04ff02ffff04ff5fffff04ff3bffff04ffff02ffff03ff17ffff01ff09ff2dffff0bff27ffff02ff36ffff04ff02ffff04ff29ffff04ff57ffff04ffff0bff2cff81b980ffff04ff59ff80808080808080ff81b78080ff8080ff0180ffff04ff17ffff04ff05ffff04ff8202ffffff04ffff04ffff04ff24ffff04ffff0bff7cff2fff82017f80ff808080ffff04ffff04ff30ffff04ffff0bff81bfffff0bff7cff15ffff10ff82017fffff11ff8202dfff2b80ff8202ff808080ff808080ff138080ff80808080808080808080ff018080ffff04ffff01a072dec062874cd4d3aab892a0906688a1ae412b0109982e1797a170add88bdcdcffff04ffff01a06d95dae356e32a71db5ddcb42224754a02524c615c5fc35f568c2af04774e589ffff04ffff01ff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080ffff04ffff01b0a7ca4bce10200d073ef10c46e9d27c3b4e31263d4c07fbec447650fcc1b286300e8ecf25c0560f9cb5aa673247fb6a6fff018080ff0180808080 \ No newline at end of file diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 626d11b41..3ece01452 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -1,3 +1,5 @@ +import type { Program, IProgram, ITuple } from '../../../../../pkg/clvm_tools_wasm.d.ts'; + import * as fs from 'fs'; import { resolve } from 'path'; import * as assert from 'assert'; @@ -172,7 +174,7 @@ export class ChiaExample { it('works as expected in context', async () => { let bls = await bls_loader.default(); const program_text = fs.readFileSync(resolve(__dirname, '../../../content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex'),'utf-8'); - const MOD: Program = Program.from_hex(program_text); + const MOD: IProgram = Program.from_hex(program_text); let ce = new ChiaExample(MOD); let sk = bls.AugSchemeMPL.key_gen([ 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, 19, 18, 12, 89, 6, 220, @@ -184,3 +186,19 @@ it('works as expected in context', async () => { let target_puzzle = ce.puzzle_for_synthetic_public_key(pk); assert.equal(target_puzzle.sha256tree().toString(), h('30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507').toString()); }); + +const cat2_puzzle = 'ff02ffff01ff02ff5effff04ff02ffff04ffff04ff05ffff04ffff0bff2cff0580ffff04ff0bff80808080ffff04ffff02ff17ff2f80ffff04ff5fffff04ffff02ff2effff04ff02ffff04ff17ff80808080ffff04ffff0bff82027fff82057fff820b7f80ffff04ff81bfffff04ff82017fffff04ff8202ffffff04ff8205ffffff04ff820bffff80808080808080808080808080ffff04ffff01ffffffff81ca3dff46ff0233ffff3c04ff01ff0181cbffffff02ff02ffff03ff05ffff01ff02ff32ffff04ff02ffff04ff0dffff04ffff0bff22ffff0bff2cff3480ffff0bff22ffff0bff22ffff0bff2cff5c80ff0980ffff0bff22ff0bffff0bff2cff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ff0bffff01ff02ffff03ffff09ffff02ff2effff04ff02ffff04ff13ff80808080ff820b9f80ffff01ff02ff26ffff04ff02ffff04ffff02ff13ffff04ff5fffff04ff17ffff04ff2fffff04ff81bfffff04ff82017fffff04ff1bff8080808080808080ffff04ff82017fff8080808080ffff01ff088080ff0180ffff01ff02ffff03ff17ffff01ff02ffff03ffff20ff81bf80ffff0182017fffff01ff088080ff0180ffff01ff088080ff018080ff0180ffff04ffff04ff05ff2780ffff04ffff10ff0bff5780ff778080ff02ffff03ff05ffff01ff02ffff03ffff09ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff01818f80ffff01ff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ffff04ff81b9ff82017980ff808080808080ffff01ff02ff5affff04ff02ffff04ffff02ffff03ffff09ff11ff7880ffff01ff04ff78ffff04ffff02ff36ffff04ff02ffff04ff13ffff04ff29ffff04ffff0bff2cff5b80ffff04ff2bff80808080808080ff398080ffff01ff02ffff03ffff09ff11ff2480ffff01ff04ff24ffff04ffff0bff20ff2980ff398080ffff010980ff018080ff0180ffff04ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff04ffff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ff17ff808080808080ff80808080808080ff0180ffff01ff04ff80ffff04ff80ff17808080ff0180ffffff02ffff03ff05ffff01ff04ff09ffff02ff26ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff0bff22ffff0bff2cff5880ffff0bff22ffff0bff22ffff0bff2cff5c80ff0580ffff0bff22ffff02ff32ffff04ff02ffff04ff07ffff04ffff0bff2cff2c80ff8080808080ffff0bff2cff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bff2cff058080ff0180ffff04ffff04ff28ffff04ff5fff808080ffff02ff7effff04ff02ffff04ffff04ffff04ff2fff0580ffff04ff5fff82017f8080ffff04ffff02ff7affff04ff02ffff04ff0bffff04ff05ffff01ff808080808080ffff04ff17ffff04ff81bfffff04ff82017fffff04ffff0bff8204ffffff02ff36ffff04ff02ffff04ff09ffff04ff820affffff04ffff0bff2cff2d80ffff04ff15ff80808080808080ff8216ff80ffff04ff8205ffffff04ff820bffff808080808080808080808080ff02ff2affff04ff02ffff04ff5fffff04ff3bffff04ffff02ffff03ff17ffff01ff09ff2dffff0bff27ffff02ff36ffff04ff02ffff04ff29ffff04ff57ffff04ffff0bff2cff81b980ffff04ff59ff80808080808080ff81b78080ff8080ff0180ffff04ff17ffff04ff05ffff04ff8202ffffff04ffff04ffff04ff24ffff04ffff0bff7cff2fff82017f80ff808080ffff04ffff04ff30ffff04ffff0bff81bfffff0bff7cff15ffff10ff82017fffff11ff8202dfff2b80ff8202ff808080ff808080ff138080ff80808080808080808080ff018080'; + +const cat2_curried_program = 'ff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080ffff04ffff01b0a7ca4bce10200d073ef10c46e9d27c3b4e31263d4c07fbec447650fcc1b286300e8ecf25c0560f9cb5aa673247fb6a6fff018080'; + +it('can uncurry an example program', async () => { + let to_uncurry_text = fs.readFileSync(resolve(__dirname, '../../../content/test_cat2_program.hex'),'utf-8'); + const program: IProgram = Program.from_hex(to_uncurry_text); + const uncurried = program.uncurry_error(); + assert.equal(uncurried.length, 2); + assert.equal(uncurried[1].length, 3); + assert.equal(uncurried[0].toString(), cat2_puzzle); + assert.equal(uncurried[1][0].toString(), 'a072dec062874cd4d3aab892a0906688a1ae412b0109982e1797a170add88bdcdc'); + assert.equal(uncurried[1][1].toString(), 'a06d95dae356e32a71db5ddcb42224754a02524c615c5fc35f568c2af04774e589'); + assert.equal(uncurried[1][2].toString(), cat2_curried_program); +}); From 64f91db57e96713091b6b30458cc09758c10483a Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 3 Oct 2023 10:10:48 -0700 Subject: [PATCH 177/196] Tested out the types, better. --- wasm/src/objects.rs | 4 +- .../src/lib/tests/index.test.ts | 116 +++++++++--------- 2 files changed, 61 insertions(+), 59 deletions(-) diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index 481feac29..e770d26d4 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -291,7 +291,7 @@ interface IProgram { curry(args: [IProgram]): IProgram; sha256tree(): [Uint8Array]; uncurry_error(): [IProgram]; - uncurry(): [IProgram|null]; + uncurry(): [IProgram, Array|null]; } "#; @@ -821,7 +821,7 @@ impl Program { if let Ok(res) = Program::uncurry_error_internal(obj) { Ok(res) } else { - Ok(vec![obj.clone().unchecked_into::(), Program::null()?]) + Ok(vec![obj.clone().unchecked_into::(), JsValue::null().unchecked_into::()]) } } } diff --git a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts index 3ece01452..b8420fa89 100644 --- a/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts +++ b/wasm/tests/clvm-tools-interface/src/lib/tests/index.test.ts @@ -7,31 +7,31 @@ import * as bls_loader from 'bls-signatures'; const {h, t, Program} = require('../../../../../pkg/clvm_tools_wasm'); it('Has BLS signatures support', async () => { - let bls = await bls_loader.default(); - let g1element = new bls.G1Element(); - let converted_g1_element = Program.to(g1element); + const bls = await bls_loader.default(); + const g1element = new bls.G1Element(); + const converted_g1_element = Program.to(g1element); assert.equal('b0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', converted_g1_element.toString()); }); it('Has the "h" function', async () => { - let unhexed = h('21203031'); + const unhexed = h('21203031'); assert.equal([0x21, 0x20, 0x30, 0x31].toString(), unhexed.toString()); }); it('Converts to string', async () => { - let converted_sexp = Program.to([1, 2, 3]); + const converted_sexp = Program.to([1, 2, 3]); assert.equal("ff01ff02ff0380", converted_sexp.toString()); }); it('Accepts already converted objects', async () => { - let converted_sexp = Program.to([1, 2, 3]); - let twice_converted = Program.to(converted_sexp); + const converted_sexp = Program.to([1, 2, 3]); + const twice_converted = Program.to(converted_sexp); assert.equal("ff01ff02ff0380", twice_converted.toString()); }); it('Has as_pair', async () => { - let converted_sexp = Program.to([1, 2, 3]); - let as_pair = converted_sexp.as_pair(); + const converted_sexp = Program.to([1, 2, 3]); + const as_pair = converted_sexp.as_pair(); assert.equal("01", as_pair[0].toString()); assert.equal("ff02ff0380", as_pair[1].toString()); }); @@ -41,17 +41,17 @@ it('Has null', async () => { }); it('Has listp', async () => { - let is_list = Program.to([1,2,3]); - let isnt_list = Program.to(456); + const is_list: IProgram = Program.to([1,2,3]); + const isnt_list: IProgram = Program.to(456); assert.equal(is_list.listp(), true); assert.equal(isnt_list.listp(), false); }); it('Has nullp', async () => { - let is_null = Program.to([]); - let is_also_null = Program.to(0); - let isnt_null = Program.to(7); - let isnt_also_null = Program.to([99,101]); + const is_null = Program.to([]); + const is_also_null = Program.to(0); + const isnt_null = Program.to(7); + const isnt_also_null = Program.to([99,101]); assert.equal(is_null.nullp(), true); assert.equal(is_also_null.nullp(), true); assert.equal(isnt_null.nullp(), false); @@ -59,111 +59,113 @@ it('Has nullp', async () => { }); it('Has as_int', async () => { - let int_value = Program.to(7).as_int(); + const int_value = Program.to(7).as_int(); assert.equal(int_value, 7); try { - non_int_value = Program.to([7,13]).as_int(); - assert.fail(true); + /*const non_int_value =*/ Program.to([7,13]).as_int(); + assert.fail('was an int but should not be'); } catch (e) { assert.equal(e.toString(), "not a number"); } }); it('Has as_bigint', async () => { - let int_value = Program.to(10000000000000000000000n).as_bigint(); + const int_value = Program.to(10000000000000000000000n).as_bigint(); assert.equal(int_value, 10000000000000000000000n); try { - non_int_value = Program.to([7,13]).as_bigint(); - assert.fail(true); + /*const non_int_value =*/ Program.to([7,13]).as_bigint(); + assert.fail(''); } catch (e) { assert.equal(e.toString(), "not a number"); } }); it('Has first and rest', async () => { - let test_list = Program.to([7,13,17,23]); + const test_list = Program.to([7,13,17,23]); assert.equal(test_list.first().toString(), '07'); assert.equal(test_list.rest().toString(), 'ff0dff11ff1780'); try { Program.to([]).first(); - assert.fail(true); + assert.fail("empty list had first"); } catch (e) { assert.equal(e.toString(), "not a cons"); } try { Program.to([]).rest(); - assert.fail(true); + assert.fail("empty list had rest"); } catch (e) { assert.equal(e.toString(), "not a cons"); } }); it('Has cons', async () => { - let test_1 = Program.to(7); - let test_2 = Program.to([8,9,10]); - let consed = test_1.cons(test_2); - let test_3 = Program.to([7,8,9,10]); + const test_1 = Program.to(7); + const test_2 = Program.to([8,9,10]); + const consed = test_1.cons(test_2); + const test_3 = Program.to([7,8,9,10]); assert.equal(consed.toString(), test_3.toString()); }); it('Has the t function', async () => { - let p1 = Program.to(7); - let p2 = Program.to(9); - let tuple = t(p1, p2); - let consed = p1.cons(p2); + const p1 = Program.to(7); + const p2 = Program.to(9); + const tuple: ITuple = t(p1, p2); + const consed = p1.cons(p2); assert.equal(Program.to(tuple).toString(), consed.toString()); }); it('Has as_bin', async () => { - let test_data = Program.to([7,8,9,10]); - let as_bin = test_data.as_bin(); + const test_data = Program.to([7,8,9,10]); + const as_bin = test_data.as_bin(); assert.equal([255,7,255,8,255,9,255,10,128].toString(), as_bin.toString()); }); it('Has list_len', async () => { - let list_data = Program.to([7,8,9,10]); - let list_len = list_data.list_len(); + const list_data = Program.to([7,8,9,10]); + const list_len = list_data.list_len(); assert.equal(list_len, 4); - let not_list = Program.to(16); - let not_list_len = not_list.list_len(); + const not_list = Program.to(16); + const not_list_len = not_list.list_len(); assert.equal(not_list_len, 0); }); it('Has equal_to', async () => { - let p1 = Program.to([7,8,[9,10],11]); - let p2 = Program.from_hex('ff07ff08ffff09ff0a80ff0b80'); - let p3 = Program.to([7,8,[9,11],11]); + const p1 = Program.to([7,8,[9,10],11]); + const p2 = Program.from_hex('ff07ff08ffff09ff0a80ff0b80'); + const p3 = Program.to([7,8,[9,11],11]); assert.ok(p1.equal_to(p2)); assert.ok(!p1.equal_to(p3)); assert.ok(!p2.equal_to(p3)); }); it('Has as_javascript', async () => { - let tuple = t(9,(t(10,11))); - let original = [7,8,tuple,12]; - let p1 = Program.to(original); - let p1_as_js = p1.as_javascript(); + const tuple = t(9,(t(10,11))); + const original = [7,8,tuple,12]; + const p1 = Program.to(original); + const p1_as_js = p1.as_javascript(); assert.equal(original.toString(), p1_as_js.toString()); }); it('Has run', async () => { - let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); - let args = Program.to([13]); + const program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); + const args = Program.to([13]); const [cost, run_result] = program.run(args); assert.equal(run_result.toString(), '8200a8'); assert.equal(cost, 2658); }); it('Has curry', async () => { - let program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); - let program_with_arg = program.curry(Program.to(13)); + const program = Program.from_hex('ff12ffff10ff02ffff010180ffff11ff02ffff01018080'); + const program_with_arg = program.curry(Program.to(13)); const [cost, run_result] = program_with_arg.run(Program.to([])); assert.equal(run_result.toString(), '8200a8'); assert.equal(cost, 2884); }); export class ChiaExample { - constructor(MOD) { + private MOD: IProgram; + + constructor(MOD: IProgram) { this.MOD = MOD; } public puzzle_for_synthetic_public_key(synthetic_public_key: G1Element): Program { @@ -172,18 +174,18 @@ export class ChiaExample { } it('works as expected in context', async () => { - let bls = await bls_loader.default(); + const bls = await bls_loader.default(); const program_text = fs.readFileSync(resolve(__dirname, '../../../content/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex'),'utf-8'); const MOD: IProgram = Program.from_hex(program_text); - let ce = new ChiaExample(MOD); - let sk = bls.AugSchemeMPL.key_gen([ + const ce = new ChiaExample(MOD); + const sk = bls.AugSchemeMPL.key_gen([ 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, 12, 62, 89, 110, 182, 9, 44, 20, 254, 22 ]); - let pk = bls.AugSchemeMPL.sk_to_g1(sk); + const pk = bls.AugSchemeMPL.sk_to_g1(sk); // pk bytes 86243290bbcbfd9ae75bdece7981965350208eb5e99b04d5cd24e955ada961f8c0a162dee740be7bdc6c3c0613ba2eb1 // Expected puzzle hash = 30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507 - let target_puzzle = ce.puzzle_for_synthetic_public_key(pk); + const target_puzzle = ce.puzzle_for_synthetic_public_key(pk); assert.equal(target_puzzle.sha256tree().toString(), h('30cdae3d54778db5eba21584c452cfb1a278136b2ec352ba44a52078efea7507').toString()); }); @@ -192,9 +194,9 @@ const cat2_puzzle = 'ff02ffff01ff02ff5effff04ff02ffff04ffff04ff05ffff04ffff0bff2 const cat2_curried_program = 'ff02ffff01ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080ffff04ffff01b0a7ca4bce10200d073ef10c46e9d27c3b4e31263d4c07fbec447650fcc1b286300e8ecf25c0560f9cb5aa673247fb6a6fff018080'; it('can uncurry an example program', async () => { - let to_uncurry_text = fs.readFileSync(resolve(__dirname, '../../../content/test_cat2_program.hex'),'utf-8'); + const to_uncurry_text = fs.readFileSync(resolve(__dirname, '../../../content/test_cat2_program.hex'),'utf-8'); const program: IProgram = Program.from_hex(to_uncurry_text); - const uncurried = program.uncurry_error(); + const uncurried: Array = program.uncurry_error(); assert.equal(uncurried.length, 2); assert.equal(uncurried[1].length, 3); assert.equal(uncurried[0].toString(), cat2_puzzle); From 0fb1e15faddc2f73e17967a216b5a7ba9d2816e7 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 3 Oct 2023 10:19:42 -0700 Subject: [PATCH 178/196] fmt + clippy --- wasm/src/api.rs | 68 ++++++----- wasm/src/jsval.rs | 95 ++++++++------- wasm/src/objects.rs | 276 ++++++++++++++++++++++---------------------- 3 files changed, 229 insertions(+), 210 deletions(-) diff --git a/wasm/src/api.rs b/wasm/src/api.rs index 445391b7f..ddbc8af3e 100644 --- a/wasm/src/api.rs +++ b/wasm/src/api.rs @@ -12,7 +12,14 @@ use wasm_bindgen::JsCast; use clvmr::allocator::Allocator; -use clvm_tools_rs::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType}; +use crate::jsval::{ + btreemap_to_object, get_property, js_object_from_sexp, js_pair, object_to_value, + read_string_to_string_map, sexp_from_js_object, +}; +use crate::objects::Program; +use clvm_tools_rs::classic::clvm::__type_compatibility__::{ + Bytes, Stream, UnvalidatedBytesFromType, +}; use clvm_tools_rs::classic::clvm::serialize::sexp_to_stream; use clvm_tools_rs::classic::clvm_tools::clvmc::compile_clvm_inner; use clvm_tools_rs::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; @@ -30,11 +37,6 @@ use clvm_tools_rs::compiler::repl::Repl; use clvm_tools_rs::compiler::runtypes::RunFailure; use clvm_tools_rs::compiler::sexp::SExp; use clvm_tools_rs::compiler::srcloc::Srcloc; -use crate::jsval::{ - btreemap_to_object, get_property, js_object_from_sexp, js_pair, object_to_value, - read_string_to_string_map, sexp_from_js_object, -}; -use crate::objects::Program; #[cfg(feature = "wee_alloc")] #[global_allocator] @@ -117,20 +119,14 @@ pub fn create_clvm_runner_err(error: String) -> JsValue { fn create_clvm_runner_run_failure(err: &RunFailure) -> JsValue { match err { - RunFailure::RunErr(l, e) => { - create_clvm_runner_err(format!("{}: Error {}", l, e)) - } - RunFailure::RunExn(l, e) => { - create_clvm_runner_err(format!("{}: Exn {}", l, e)) - } + RunFailure::RunErr(l, e) => create_clvm_runner_err(format!("{}: Error {}", l, e)), + RunFailure::RunExn(l, e) => create_clvm_runner_err(format!("{}: Exn {}", l, e)), } } fn create_clvm_compile_failure(err: &CompileErr) -> JsValue { match err { - CompileErr(l, e) => { - create_clvm_runner_err(format!("{}: Error {}", l, e)) - } + CompileErr(l, e) => create_clvm_runner_err(format!("{}: Error {}", l, e)), } } @@ -144,7 +140,12 @@ impl CldbSingleBespokeOverride for JsBespokeOverride { // When the user returns, try to convert the result back to sexp. fn get_override(&self, env: Rc) -> Result, RunFailure> { let args = js_sys::Array::new(); - args.set(0, js_object_from_sexp(env.clone()).map_err(|_| RunFailure::RunErr(env.loc(), "error converting override value".to_string()))?); + args.set( + 0, + js_object_from_sexp(env.clone()).map_err(|_| { + RunFailure::RunErr(env.loc(), "error converting override value".to_string()) + })?, + ); self.fun .apply(&JsValue::null(), &args) .map_err(|e| { @@ -247,7 +248,9 @@ pub fn create_clvm_runner( #[wasm_bindgen] pub fn final_value(runner: i32) -> JsValue { with_runner(runner, |r| { - r.cldbrun.final_result().map(|v| js_object_from_sexp(v).unwrap_or_else(|e| e)) + r.cldbrun + .final_result() + .map(|v| js_object_from_sexp(v).unwrap_or_else(|e| e)) }) .unwrap_or_else(JsValue::null) } @@ -280,7 +283,10 @@ fn make_compile_output(result_stream: &Stream, symbol_table: &HashMap { - return create_clvm_compile_failure(&CompileErr( - program.loc(), - e.to_string(), - )); - }, - Ok(x) => x, - }; + let hash_bytes = + match Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(function_hash.clone()))) { + Err(e) => { + return create_clvm_compile_failure(&CompileErr(program.loc(), e.to_string())); + } + Ok(x) => x, + }; let function_path = match path_to_function(main_env.1.clone(), &hash_bytes.data().clone()) { Some(p) => p, @@ -489,11 +492,14 @@ pub fn sexp_to_string(v: &JsValue) -> JsValue { #[wasm_bindgen] pub fn h(v: String) -> Result, JsValue> { - let hex_data = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(v))).map_err(|_| js_sys::JsString::from("bad hex input"))?; + let hex_data = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(v))) + .map_err(|_| js_sys::JsString::from("bad hex input"))?; Ok(hex_data.data().clone()) } #[wasm_bindgen] pub fn t(a: &JsValue, b: &JsValue) -> Result { - Program::as_pair_internal(&Program::cons_internal(&Program::to_internal(a)?, &Program::to_internal(b)?)?.into()) + Program::as_pair_internal( + &Program::cons_internal(&Program::to_internal(a)?, &Program::to_internal(b)?)?.into(), + ) } diff --git a/wasm/src/jsval.rs b/wasm/src/jsval.rs index 0b9a65e13..1fed2faee 100644 --- a/wasm/src/jsval.rs +++ b/wasm/src/jsval.rs @@ -1,4 +1,3 @@ -use js_sys; use js_sys::JSON::stringify; use js_sys::{Array, BigInt, Object, Reflect}; use wasm_bindgen::JsCast; @@ -42,21 +41,27 @@ pub fn js_object_from_sexp(v: Rc) -> Result { match v.borrow() { SExp::Nil(_) => Ok(JsValue::null()), SExp::Integer(_, i) => Ok(JsValue::bigint_from_str(&i.to_string())), - SExp::QuotedString(_, _, q) => { - Ok(JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode())) - } - SExp::Atom(_, q) => { - Ok(JsValue::from_str(&Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode())) - } + SExp::QuotedString(_, _, q) => Ok(JsValue::from_str( + &Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode(), + )), + SExp::Atom(_, q) => Ok(JsValue::from_str( + &Bytes::new(Some(BytesFromType::Raw(q.clone()))).decode(), + )), SExp::Cons(_, a, b) => { if let Some(lst) = v.proper_list() { let array = Array::new(); - for i in 0..lst.len() { - array.set(i as u32, js_object_from_sexp(Rc::new(lst[i].clone())).unwrap_or_else(|e| e)); + for (i, _) in lst.iter().enumerate() { + array.set( + i as u32, + js_object_from_sexp(Rc::new(lst[i].clone())).unwrap_or_else(|e| e), + ); } Ok(array_to_value(array)) } else { - t(&js_object_from_sexp(a.clone())?, &js_object_from_sexp(b.clone())?) + t( + &js_object_from_sexp(a.clone())?, + &js_object_from_sexp(b.clone())?, + ) } } } @@ -103,7 +108,7 @@ fn location(o: &Object) -> Option { line: l, col: c, until: get_property(o, "until") - .and_then(|lo| Object::try_from(&lo).map(|o| o.clone())) + .and_then(|lo| Object::try_from(&lo).cloned()) .and_then(|lo| location_lc_pair(&lo)) .map(|(ll, lc)| Until { line: ll, col: lc }), }) @@ -111,25 +116,29 @@ fn location(o: &Object) -> Option { pub fn detect_serializable(loc: &Srcloc, v: &JsValue) -> Option> { let serialize_key = JsValue::from_str("serialize"); - js_sys::Reflect::get(v, &serialize_key).ok().and_then(|serialize| { - Reflect::apply(serialize.unchecked_ref(), v, &js_sys::Array::new()).ok().and_then(|array| { - Array::try_from(array).ok().and_then(|array| { - let mut bytes_array: Vec = vec![]; - for item in array.iter() { - if let Some(n) = item.as_f64() { - if n < 0.0 || n > 255.0 { - return None; + js_sys::Reflect::get(v, &serialize_key) + .ok() + .and_then(|serialize| { + Reflect::apply(serialize.unchecked_ref(), v, &js_sys::Array::new()) + .ok() + .and_then(|array| { + Array::try_from(array).ok().and_then(|array| { + let mut bytes_array: Vec = vec![]; + for item in array.iter() { + if let Some(n) = item.as_f64() { + if !(0.0..=255.0).contains(&n) { + return None; + } + bytes_array.push(n as u8); + } else { + return None; + } } - bytes_array.push(n as u8); - } else { - return None; - } - } - return Some(Rc::new(SExp::QuotedString(loc.clone(), b'x', bytes_array))); - }) + Some(Rc::new(SExp::QuotedString(loc.clone(), b'x', bytes_array))) + }) + }) }) - }) } pub fn detect_convertible(v: &JsValue) -> Result, JsValue> { @@ -146,9 +155,9 @@ pub fn detect_convertible(v: &JsValue) -> Result, JsValue> { pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { // Already converted value. if let Ok(res) = js_cache_value_from_js(v) { - find_cached_sexp(res.entry, &res.content).map(|result| { - result.modern.clone() - }).ok() + find_cached_sexp(res.entry, &res.content) + .map(|result| result.modern.clone()) + .ok() } else if v.is_bigint() { BigInt::new(v) .ok() @@ -157,22 +166,20 @@ pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { .and_then(|v| v.parse::().ok()) .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) } else if let Some(fval) = v.as_f64() { - (fval as i64).to_bigint() + (fval as i64) + .to_bigint() .map(|x| Rc::new(SExp::Integer(sstart.clone(), x))) } else if let Some(g1_bytes) = detect_serializable(&sstart, v) { Some(g1_bytes) - } else if let Some(converted) = detect_convertible(v).ok() { + } else if let Ok(converted) = detect_convertible(v) { Some(converted) } else if Array::is_array(v) { let a = Array::from(v); - let mut result_value = Rc::new(SExp::Nil(Srcloc::start(&"*js*".to_string()))); + let mut result_value = Rc::new(SExp::Nil(Srcloc::start("*js*"))); for i_rev in 0..a.length() { let i = a.length() - i_rev - 1; - match sexp_from_js_object(sstart.clone(), &a.get(i)) { - Some(nv) => { - result_value = Rc::new(SExp::Cons(nv.loc(), nv, result_value)); - } - _ => {} + if let Some(nv) = sexp_from_js_object(sstart.clone(), &a.get(i)) { + result_value = Rc::new(SExp::Cons(nv.loc(), nv, result_value)); } } Some(result_value) @@ -180,7 +187,7 @@ pub fn sexp_from_js_object(sstart: Srcloc, v: &JsValue) -> Option> { Object::try_from(v) .map(|o| { let loc = get_property(o, "location") - .and_then(|o| Object::try_from(&o).map(|o| o.clone())) + .and_then(|o| Object::try_from(&o).cloned()) .and_then(|o| location(&o)) .unwrap_or_else(|| sstart.clone()); get_property(o, "pair") @@ -211,21 +218,21 @@ pub fn btreemap_to_object<'a>(iter: impl Iterator Result, String> { let mut result = HashMap::new(); - for ent in js_sys::Object::keys(&symbols).values() { + for ent in js_sys::Object::keys(symbols).values() { let key = ent.unwrap().as_string().unwrap(); - match get_property(&symbols, &key).unwrap().as_string() { + match get_property(symbols, &key).unwrap().as_string() { Some(val) => { result.insert(key, val); } diff --git a/wasm/src/objects.rs b/wasm/src/objects.rs index e770d26d4..fa6932402 100644 --- a/wasm/src/objects.rs +++ b/wasm/src/objects.rs @@ -8,14 +8,18 @@ use std::rc::Rc; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; -use clvmr::Allocator; -use clvm_tools_rs::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType, bi_one}; -use clvm_tools_rs::classic::clvm::serialize::{SimpleCreateCLVMObject, sexp_to_stream, sexp_from_stream}; +use clvm_tools_rs::classic::clvm::__type_compatibility__::{ + bi_one, Bytes, Stream, UnvalidatedBytesFromType, +}; +use clvm_tools_rs::classic::clvm::serialize::{ + sexp_from_stream, sexp_to_stream, SimpleCreateCLVMObject, +}; use clvm_tools_rs::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; use clvm_tools_rs::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, sha256tree, truthy}; use clvm_tools_rs::compiler::prims::{primapply, primcons, primquote}; use clvm_tools_rs::compiler::sexp::SExp; use clvm_tools_rs::compiler::srcloc::Srcloc; +use clvmr::Allocator; use crate::api::{create_clvm_runner_err, get_next_id}; use crate::jsval::{js_object_from_sexp, sexp_from_js_object}; @@ -41,20 +45,21 @@ struct ObjectCache { pub struct JsCacheValue { pub entry: i32, - pub content: String + pub content: String, } pub fn js_cache_value_from_js(jsval: &JsValue) -> Result { - let entry = js_sys::Reflect::get( - jsval, - &JsString::from("id") - )?.as_f64().ok_or(JsString::from("id was not a number"))?; - let content = js_sys::Reflect::get( - jsval, - &JsString::from("content") - )?.as_string().ok_or(JsString::from("content was not a string"))?; - - Ok(JsCacheValue { entry: entry as i32, content }) + let entry = js_sys::Reflect::get(jsval, &JsString::from("id"))? + .as_f64() + .ok_or(JsString::from("id was not a number"))?; + let content = js_sys::Reflect::get(jsval, &JsString::from("content"))? + .as_string() + .ok_or(JsString::from("content was not a string"))?; + + Ok(JsCacheValue { + entry: entry as i32, + content, + }) } impl Default for ObjectCache { @@ -85,45 +90,47 @@ impl ObjectCache { fn create_entry_from_sexp(&mut self, id: i32, sexp: Rc) -> Result { let mut allocator = Allocator::new(); - let node = convert_to_clvm_rs( - &mut allocator, - sexp.clone() - ).map_err(|_| js_sys::JsString::from("could not convert to clvm"))?; + let node = convert_to_clvm_rs(&mut allocator, sexp.clone()) + .map_err(|_| js_sys::JsString::from("could not convert to clvm"))?; let mut stream = Stream::new(None); sexp_to_stream(&mut allocator, node, &mut stream); - self.create_or_update_cache_entry(id, ObjectCacheMember { - modern: sexp.clone(), - }); + self.create_or_update_cache_entry( + id, + ObjectCacheMember { + modern: sexp.clone(), + }, + ); Ok(stream.get_value().hex()) } - fn find_or_create_entry_from_hex(&mut self, entry: i32, content: &str) -> Result { + fn find_or_create_entry_from_hex( + &mut self, + entry: i32, + content: &str, + ) -> Result { if let Some(res) = self.cache_data.get(&entry) { return Ok(res.clone()); } let mut allocator = Allocator::new(); - let bytes_from_hex = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(content.to_string()))).map_err(|_| JsString::from("could not parse hex"))?; + let bytes_from_hex = + Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(content.to_string()))) + .map_err(|_| JsString::from("could not parse hex"))?; let mut stream = Stream::new(Some(bytes_from_hex)); let parsed = sexp_from_stream( &mut allocator, &mut stream, - Box::new(SimpleCreateCLVMObject {}) + Box::new(SimpleCreateCLVMObject {}), ) - .map(|x| x.1) - .map_err(|_| JsString::from("could not parse sexp from hex"))?; + .map(|x| x.1) + .map_err(|_| JsString::from("could not parse sexp from hex"))?; let srcloc = Srcloc::start("*var*"); - let modern = convert_from_clvm_rs( - &mut allocator, - srcloc, - parsed - ).map_err(|_| JsString::from("could not realize parsed sexp"))?; + let modern = convert_from_clvm_rs(&mut allocator, srcloc, parsed) + .map_err(|_| JsString::from("could not realize parsed sexp"))?; - let cache_entry = ObjectCacheMember { - modern - }; + let cache_entry = ObjectCacheMember { modern }; self.create_or_update_cache_entry(entry, cache_entry.clone()); Ok(cache_entry) @@ -223,13 +230,11 @@ static PROGRAM_FUNCTIONS: &[FunctionWrapperDesc] = &[ }, ]; -static TUPLE_FUNCTIONS: &[FunctionWrapperDesc] = &[ - FunctionWrapperDesc { - export_name: "to_program", - member_name: "tuple_to_program_internal", - varargs: false - }, -]; +static TUPLE_FUNCTIONS: &[FunctionWrapperDesc] = &[FunctionWrapperDesc { + export_name: "to_program", + member_name: "tuple_to_program_internal", + varargs: false, +}]; thread_local! { static OBJECT_CACHE: RefCell = { @@ -257,7 +262,7 @@ fn get_srcloc() -> Srcloc { pub fn find_cached_sexp(entry: i32, content: &str) -> Result { if content == "80" { return Ok(ObjectCacheMember { - modern: Rc::new(SExp::Nil(get_srcloc())) + modern: Rc::new(SExp::Nil(get_srcloc())), }); } @@ -319,7 +324,7 @@ extern "C" { // The object's prototype will include methods for Program, such as cons and call // the real static methods of Program. #[wasm_bindgen(inspectable)] -pub struct Program { } +pub struct Program {} // Build prototype fn get_program_prototype() -> Result { @@ -332,12 +337,11 @@ fn get_program_prototype() -> Result { let program_self = js_sys::eval("Program")?; for func_wrapper_desc in PROGRAM_FUNCTIONS.iter() { - let pass_on_args = - if func_wrapper_desc.varargs { - "[args]" - } else { - "args" - }; + let pass_on_args = if func_wrapper_desc.varargs { + "[args]" + } else { + "args" + }; let to_string_fun = js_sys::Function::new_with_args( "", &format!("const t = this; return function() {{ let args = Array.prototype.slice.call(arguments); let apply_args = {pass_on_args}; apply_args.unshift(this); return t.{}.apply(null, apply_args); }}", func_wrapper_desc.member_name) @@ -391,10 +395,7 @@ pub fn finish_new_object(id: i32, encoded_hex: &str) -> Result let prototype = get_program_prototype()?; let new_object = js_sys::Object::new(); - js_sys::Reflect::set_prototype_of( - &new_object, - &prototype - )?; + js_sys::Reflect::set_prototype_of(&new_object, &prototype)?; js_sys::Reflect::set( &new_object, @@ -412,27 +413,38 @@ pub fn finish_new_object(id: i32, encoded_hex: &str) -> Result // Return a vector of arguments if the given SExp is the expected operator // and has the required number of arguments. -fn match_op(opcode: u8, mut expected_args: usize, opname: &str, program: Rc) -> Result>, JsValue> { - let plist = - if expected_args == 0 { - if let SExp::Cons(_, a, b) = program.borrow() { - let a_borrowed: &SExp = a.borrow(); - let b_borrowed: &SExp = b.borrow(); - expected_args = 1; - vec![a_borrowed.clone(), b_borrowed.clone()] - } else { - return Err(JsValue::from_str(&format!("program was expected to be a cons, but wasn't: {program}"))); - } - } else if let Some(plist) = program.proper_list() { - plist +fn match_op( + opcode: u8, + mut expected_args: usize, + opname: &str, + program: Rc, +) -> Result>, JsValue> { + let plist = if expected_args == 0 { + if let SExp::Cons(_, a, b) = program.borrow() { + let a_borrowed: &SExp = a.borrow(); + let b_borrowed: &SExp = b.borrow(); + expected_args = 1; + vec![a_borrowed.clone(), b_borrowed.clone()] } else { - // Not a list so can't be an apply. - return Err(JsValue::from_str(&format!("program wasn't a list representing an {opname} op: {program}"))); - }; + return Err(JsValue::from_str(&format!( + "program was expected to be a cons, but wasn't: {program}" + ))); + } + } else if let Some(plist) = program.proper_list() { + plist + } else { + // Not a list so can't be an apply. + return Err(JsValue::from_str(&format!( + "program wasn't a list representing an {opname} op: {program}" + ))); + }; // Not the right length if plist.len() != expected_args + 1 { - return Err(JsValue::from_str(&format!("program list wasn't a list of {} representing an {opname} op: {program}", expected_args + 1))); + return Err(JsValue::from_str(&format!( + "program list wasn't a list of {} representing an {opname} op: {program}", + expected_args + 1 + ))); } // Not an apply @@ -454,14 +466,18 @@ fn cache_and_accumulate_arg(array: &Array, prog: Rc) -> Result<(), JsValue } fn to_iprogram(v: JsValue) -> IProgram { - JsValue::from(v).unchecked_into::() + v.unchecked_into::() } #[wasm_bindgen] impl Program { pub fn to_internal(input: &JsValue) -> Result { let loc = get_srcloc(); - let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| Err(create_clvm_runner_err(format!("unable to convert to value"))))?; + let sexp = sexp_from_js_object(loc, input).map(Ok).unwrap_or_else(|| { + Err(create_clvm_runner_err(format!( + "unable to convert to value" + ))) + })?; let new_id = get_next_id(); @@ -500,10 +516,7 @@ impl Program { #[wasm_bindgen] pub fn to_string_internal(obj: &JsValue) -> Result { - js_sys::Reflect::get( - obj, - &js_sys::JsString::from("content"), - ) + js_sys::Reflect::get(obj, &js_sys::JsString::from("content")) } #[wasm_bindgen] @@ -524,15 +537,8 @@ impl Program { result_value.set(0, object_a); result_value.set(1, object_b); // Support reading as a classic clvm input. - Reflect::set( - &result_value, - &JsString::from("pair"), - &result_value, - )?; - Reflect::set_prototype_of( - &result_value, - &prototype - )?; + Reflect::set(&result_value, &JsString::from("pair"), &result_value)?; + Reflect::set_prototype_of(&result_value, &prototype)?; return Ok(result_value.into()); } @@ -555,7 +561,10 @@ impl Program { pub fn as_int_internal(obj: &JsValue) -> Result { let cacheval = js_cache_value_from_js(obj)?; let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; - let number = cached.modern.get_number().map_err(|_| JsString::from("not a number"))?; + let number = cached + .modern + .get_number() + .map_err(|_| JsString::from("not a number"))?; (number.to_i32()).ok_or(JsString::from("number out of range").into()) } @@ -563,10 +572,14 @@ impl Program { pub fn as_bigint_internal(obj: &JsValue) -> Result { let cacheval = js_cache_value_from_js(obj)?; let cached = find_cached_sexp(cacheval.entry, &cacheval.content)?; - let number = cached.modern.get_number().map_err(|_| JsString::from("not a number"))?; + let number = cached + .modern + .get_number() + .map_err(|_| JsString::from("not a number"))?; let num_string = number.to_string(); let num_str: &str = &num_string; - js_sys::BigInt::new(&JsString::from(num_str)).map_err(|_| JsString::from("couldn't construct bigint").into()) + js_sys::BigInt::new(&JsString::from(num_str)) + .map_err(|_| JsString::from("couldn't construct bigint").into()) } #[wasm_bindgen] @@ -604,7 +617,11 @@ impl Program { let other_cache = find_cached_sexp(other_val.entry, &other_val.content)?; let new_id = get_next_id(); - let new_sexp = Rc::new(SExp::Cons(get_srcloc(), cached.modern.clone(), other_cache.modern.clone())); + let new_sexp = Rc::new(SExp::Cons( + get_srcloc(), + cached.modern.clone(), + other_cache.modern.clone(), + )); let new_cached = create_cached_sexp(new_id, new_sexp)?; finish_new_object(new_id, &new_cached).map(to_iprogram) } @@ -618,41 +635,30 @@ impl Program { let arg_cache = find_cached_sexp(argval.entry, &argval.content)?; let mut allocator = Allocator::new(); - let prog_classic = convert_to_clvm_rs( - &mut allocator, - prog_cache.modern.clone() - ).map_err(|_| { - let err: JsValue = JsString::from("error converting program").into(); - err - })?; - let arg_classic = convert_to_clvm_rs( - &mut allocator, - arg_cache.modern.clone() - ).map_err(|_| { - let err: JsValue = JsString::from("error converting args").into(); - err - })?; + let prog_classic = + convert_to_clvm_rs(&mut allocator, prog_cache.modern.clone()).map_err(|_| { + let err: JsValue = JsString::from("error converting program").into(); + err + })?; + let arg_classic = + convert_to_clvm_rs(&mut allocator, arg_cache.modern.clone()).map_err(|_| { + let err: JsValue = JsString::from("error converting args").into(); + err + })?; let runner = DefaultProgramRunner::default(); - let run_result = - runner.run_program( - &mut allocator, - prog_classic, - arg_classic, - None - ).map_err(|e| { + let run_result = runner + .run_program(&mut allocator, prog_classic, arg_classic, None) + .map_err(|e| { let err_str: &str = &e.1; let err: JsValue = JsString::from(err_str).into(); err })?; - let modern_result = convert_from_clvm_rs( - &mut allocator, - get_srcloc(), - run_result.1 - ).map_err(|_| { - let err: JsValue = JsString::from("error converting result").into(); - err - })?; + let modern_result = convert_from_clvm_rs(&mut allocator, get_srcloc(), run_result.1) + .map_err(|_| { + let err: JsValue = JsString::from("error converting result").into(); + err + })?; let result_id = get_next_id(); let new_cached_result = create_cached_sexp(result_id, modern_result)?; let result_object = finish_new_object(result_id, &new_cached_result)?; @@ -664,24 +670,18 @@ impl Program { #[wasm_bindgen] pub fn tuple_to_program_internal(obj: &JsValue) -> Result { - let a = js_sys::Reflect::get( - obj, - &JsString::from("0"), - )?; - let b = js_sys::Reflect::get( - obj, - &JsString::from("1"), - )?; + let a = js_sys::Reflect::get(obj, &JsString::from("0"))?; + let b = js_sys::Reflect::get(obj, &JsString::from("1"))?; Program::cons_internal(&a, &b) } #[wasm_bindgen] pub fn as_bin_internal(obj: &JsValue) -> Result, JsValue> { - let convert = Reflect::get( - obj, - &JsString::from("content"), - )?.as_string().ok_or(JsString::from("content wasn't a hex string"))?; - let bytes = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(convert))).map_err(|_| JsString::from("could not convert to binary data"))?; + let convert = Reflect::get(obj, &JsString::from("content"))? + .as_string() + .ok_or(JsString::from("content wasn't a hex string"))?; + let bytes = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(convert))) + .map_err(|_| JsString::from("could not convert to binary data"))?; Ok(bytes.data().clone()) } @@ -752,14 +752,14 @@ impl Program { fixed_args = Rc::new(primcons( get_srcloc(), Rc::new(primquote(get_srcloc(), a_cached.modern.clone())), - fixed_args + fixed_args, )); } let result = Rc::new(primapply( get_srcloc(), Rc::new(primquote(get_srcloc(), program.modern.clone())), - fixed_args + fixed_args, )); let new_id = get_next_id(); @@ -813,7 +813,10 @@ impl Program { let new_cached_mod = create_cached_sexp(mod_id, quoted_prog[0].clone())?; let mod_js = finish_new_object(mod_id, &new_cached_mod)?; - Ok(vec![mod_js.into(), retrieved_args.unchecked_into::()]) + Ok(vec![ + mod_js.into(), + retrieved_args.unchecked_into::(), + ]) } #[wasm_bindgen] @@ -821,7 +824,10 @@ impl Program { if let Ok(res) = Program::uncurry_error_internal(obj) { Ok(res) } else { - Ok(vec![obj.clone().unchecked_into::(), JsValue::null().unchecked_into::()]) + Ok(vec![ + obj.clone().unchecked_into::(), + JsValue::null().unchecked_into::(), + ]) } } } From d19eea89523ccd26877706317b83a54f5bb958a3 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 4 Oct 2023 01:52:44 -0700 Subject: [PATCH 179/196] Bump version for improvements --- CHANGELOG.md | 9 +++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- wasm/Cargo.lock | 4 ++-- wasm/Cargo.toml | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1b58b09b..a0a8d5278 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,3 +34,12 @@ Skipped - modern lambda added - updated some internal data strucutres and call interfaces to support env variable renaming at during closure generation / lambda capture, or any step during transformation. + +## 0.1.37 + +- First npm publish with a Program-like object reminiscent of + chia.types.blockchain_format.program.Program + +## 0.1.38 + +- Uncurry fix, typescript type improvements for npm personality. diff --git a/Cargo.lock b/Cargo.lock index 9df64be37..ca77d6836 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clvm_tools_rs" -version = "0.1.37" +version = "0.1.38" dependencies = [ "binascii", "bls12_381", diff --git a/Cargo.toml b/Cargo.toml index aef8081c0..a0a465bc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clvm_tools_rs" -version = "0.1.37" +version = "0.1.38" edition = "2018" authors = ["Art Yerkes "] description = "tools for working with chialisp language; compiler, repl, python and wasm bindings" diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 7feb6b4c3..e26fc9f6f 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clvm_tools_rs" -version = "0.1.37" +version = "0.1.38" dependencies = [ "binascii", "bls12_381", @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "clvm_tools_wasm" -version = "0.1.37" +version = "0.1.38" dependencies = [ "clvm_tools_rs", "clvmr", diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index bb4a5e88a..089ca4833 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clvm_tools_wasm" -version = "0.1.37" +version = "0.1.38" edition = "2018" authors = ["Art Yerkes "] description = "tools for working with chialisp language; compiler, repl, python and wasm bindings" From 694c516dfb208a9d24ebb2ab2ea4c586741b4723 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 17 Oct 2023 21:48:53 -0700 Subject: [PATCH 180/196] Pull in some changes from staging --- src/compiler/preprocessor/macros.rs | 2 - src/compiler/preprocessor/mod.rs | 116 +++++++++++++++++----------- src/tests/classic/run.rs | 14 ++++ 3 files changed, 83 insertions(+), 49 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 4bf31b064..2267018e4 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -419,7 +419,6 @@ impl PrimOverride for PreprocessorExtension { _context: Rc, tail: Rc, ) -> Result>, RunFailure> { - eprintln!("running {head} {tail}"); if let SExp::Atom(hl, head_atom) = head.borrow() { let have_args: Vec> = if let Some(args_list) = tail.proper_list() { args_list.into_iter().map(Rc::new).collect() @@ -432,7 +431,6 @@ impl PrimOverride for PreprocessorExtension { .try_eval(hl, &have_args) .map_err(compile_to_run_err)?; - eprintln!("res = {res}"); return Ok(Some(res)); } } diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 558165fae..cbe95d9ef 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -6,6 +6,7 @@ use std::rc::Rc; use clvmr::allocator::Allocator; +use crate::classic::clvm_tools::binutils::assemble; use crate::classic::clvm_tools::clvmc::compile_clvm_text_maybe_opt; use crate::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; @@ -16,9 +17,9 @@ use crate::compiler::compiler::compile_from_compileform; use crate::compiler::comptypes::{ BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, IncludeDesc, IncludeProcessType, }; -use crate::compiler::dialect::KNOWN_DIALECTS; +use crate::compiler::dialect::{detect_modern, KNOWN_DIALECTS}; use crate::compiler::evaluate::{create_argument_captures, ArgInputs}; -use crate::compiler::frontend::compile_helperform; +use crate::compiler::frontend::{compile_helperform, frontend}; use crate::compiler::preprocessor::macros::PreprocessorExtension; use crate::compiler::rename::rename_args_helperform; use crate::compiler::runtypes::RunFailure; @@ -45,9 +46,11 @@ enum IncludeType { struct Preprocessor { opts: Rc, + ppext: Rc, runner: Rc, helpers: Vec, strict: bool, + stored_macros: HashMap, Rc>, } fn compose_defconst(loc: Srcloc, name: &[u8], sexp: Rc) -> Rc { @@ -90,17 +93,25 @@ fn nilize(v: Rc) -> Rc { impl Preprocessor { pub fn new(opts: Rc) -> Self { let runner = Rc::new(DefaultProgramRunner::new()); + let ppext = Rc::new(PreprocessorExtension::new()); + let opts_prims = ppext.enrich_prims(opts.clone()); Preprocessor { - opts: opts.clone(), + opts: opts_prims, + ppext, runner, helpers: Vec::new(), strict: opts.dialect().strict, + stored_macros: HashMap::default(), } } /// Given a specification of an include file, load up the forms inside it and /// return them (or an error if the file couldn't be read or wasn't a list). - pub fn process_include(&mut self, include: &IncludeDesc) -> Result>, CompileErr> { + pub fn process_include( + &mut self, + includes: &mut Vec, + include: &IncludeDesc, + ) -> Result>, CompileErr> { let filename_and_content = self .opts .read_new_file(self.opts.filename(), decode_string(&include.name))?; @@ -122,9 +133,8 @@ impl Preprocessor { if self.strict { let mut result = Vec::new(); for p in parsed.into_iter() { - if let Some(res) = self.expand_macros(p.clone(), true)? { - result.push(res); - } + let mut new_forms = self.process_pp_form(includes, p.clone())?; + result.append(&mut new_forms); } Ok(result) @@ -281,9 +291,6 @@ impl Preprocessor { continue; } - // as inline defuns because they're closest to that - // semantically. - let mut allocator = Allocator::new(); // The name matched, try calling it. // Form argument env. @@ -295,37 +302,46 @@ impl Preprocessor { mdata.args.clone(), )?; - let ppext = Rc::new(PreprocessorExtension::new()); - let extension: &PreprocessorExtension = ppext.borrow(); - let opts_prims = extension.enrich_prims(self.opts.clone()); - let new_program = CompileForm { - loc: body.loc(), - args: mdata.args.clone(), - include_forms: vec![], - helpers: self.helpers.clone(), - exp: mdata.body.clone(), - }; - let mut symbol_table = HashMap::new(); - let compiled_program = compile_from_compileform( - &mut allocator, - self.runner.clone(), - opts_prims.clone(), - new_program, - &mut symbol_table, - )?; + let mut allocator = Allocator::new(); + let compiled_program = + if let Some(compiled_program) = self.stored_macros.get(&mdata.name) { + compiled_program.clone() + } else { + // as inline defuns because they're closest to that + // semantically. + let mut symbol_table = HashMap::new(); + let new_program = CompileForm { + loc: body.loc(), + args: mdata.args.clone(), + include_forms: vec![], + helpers: self.helpers.clone(), + exp: mdata.body.clone(), + }; + let compiled_program = compile_from_compileform( + &mut allocator, + self.runner.clone(), + self.opts.clone(), + new_program, + &mut symbol_table, + )?; + self.stored_macros + .insert(mdata.name.clone(), Rc::new(compiled_program.clone())); + Rc::new(compiled_program) + }; + + let ppext: &PreprocessorExtension = self.ppext.borrow(); let res = clvm::run( &mut allocator, self.runner.clone(), - opts_prims.prim_map(), - Rc::new(compiled_program), + self.opts.prim_map(), + compiled_program, args.clone(), - Some(extension), + Some(ppext), None, ) .map(nilize) .map_err(CompileErr::from)?; - eprintln!("macro {} {args} => {res}", decode_string(&name)); return Ok(Some(res)); } } @@ -515,7 +531,7 @@ impl Preprocessor { Ok(vec![]) } else if let Some(IncludeType::Basic(i)) = &included { self.recurse_dependencies(includes, IncludeProcessType::Compiled, i.clone())?; - self.process_include(i) + self.process_include(includes, i) } else if let Some(IncludeType::Processed(f, kind, name)) = &included { self.recurse_dependencies(includes, kind.clone(), f.clone())?; self.process_embed(body.loc(), &decode_string(&f.name), kind, name) @@ -588,24 +604,30 @@ pub fn preprocess( /// form that causes compilation to include another file. The file names are path /// expanded based on the include path they were found in (from opts). pub fn gather_dependencies( - opts: Rc, + mut opts: Rc, real_input_path: &str, file_content: &str, ) -> Result, CompileErr> { - let mut includes = Vec::new(); - let no_stdenv_opts = opts.set_stdenv(false); - let mut p = Preprocessor::new(no_stdenv_opts); - let loc = Srcloc::start(real_input_path); - - let parsed = parse_sexp(loc, file_content.bytes())?; - - if parsed.is_empty() { - return Ok(vec![]); + let mut allocator = Allocator::new(); + + let assembled_input = assemble(&mut allocator, &file_content).map_err(|e| { + CompileErr(Srcloc::start(real_input_path), e.1) + })?; + let dialect = detect_modern(&mut allocator, assembled_input); + opts = opts.set_stdenv(dialect.strict).set_dialect(dialect.clone()); + if let Some(stepping) = dialect.stepping { + opts = opts + .set_optimize(stepping > 22) + .set_frontend_opt(stepping > 21); } - for elt in parsed.iter() { - p.run(&mut includes, elt.clone())?; - } + let parsed = parse_sexp(Srcloc::start(real_input_path), file_content.bytes())?; + let program = frontend(opts, &parsed)?; - Ok(includes) + let filtered_results: Vec = program + .include_forms + .into_iter() + .filter(|f| !f.name.starts_with(b"*")) + .collect(); + Ok(filtered_results) } diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 94b93010a..318a59912 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1561,3 +1561,17 @@ fn test_continued_if() { .to_string(); assert_eq!(res.to_string(), "0x0304050d630090"); } + +#[test] +fn test_preprocess_can_recurse() { + let prog = "resources/tests/strict/test-inner-include.clsp".to_string(); + let res = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + prog.clone(), + ]) + .trim() + .to_string(); + assert_eq!(res, "(2 (1 2 (3 5 (1 2 (1 18 5 (1 . 2)) 1) (1 2 (1 16 5 (1 . 1)) 1)) 1) (4 (1) 1))"); +} From 8988aeeed8257d8d9a8fd1feecc3b20fcf871e6b Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 17 Oct 2023 21:49:27 -0700 Subject: [PATCH 181/196] Add test files --- resources/tests/strict/test-inner-include.clinc | 3 +++ resources/tests/strict/test-inner-include.clsp | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 resources/tests/strict/test-inner-include.clinc create mode 100644 resources/tests/strict/test-inner-include.clsp diff --git a/resources/tests/strict/test-inner-include.clinc b/resources/tests/strict/test-inner-include.clinc new file mode 100644 index 000000000..704dfcca7 --- /dev/null +++ b/resources/tests/strict/test-inner-include.clinc @@ -0,0 +1,3 @@ +( + (include defmac_simple_if.clib) +) diff --git a/resources/tests/strict/test-inner-include.clsp b/resources/tests/strict/test-inner-include.clsp new file mode 100644 index 000000000..6fc0dabf8 --- /dev/null +++ b/resources/tests/strict/test-inner-include.clsp @@ -0,0 +1,7 @@ +(mod (X) + (include *strict-cl-21*) + + (include test-inner-include.clinc) + + (if_ X (* X 2) (+ X 1)) + ) From 555e266b6bac8bf25614be708469368e63f54950 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 17 Oct 2023 21:49:49 -0700 Subject: [PATCH 182/196] fmt --- src/compiler/preprocessor/mod.rs | 5 ++--- src/tests/classic/run.rs | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index cbe95d9ef..8c3978f9e 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -610,9 +610,8 @@ pub fn gather_dependencies( ) -> Result, CompileErr> { let mut allocator = Allocator::new(); - let assembled_input = assemble(&mut allocator, &file_content).map_err(|e| { - CompileErr(Srcloc::start(real_input_path), e.1) - })?; + let assembled_input = assemble(&mut allocator, &file_content) + .map_err(|e| CompileErr(Srcloc::start(real_input_path), e.1))?; let dialect = detect_modern(&mut allocator, assembled_input); opts = opts.set_stdenv(dialect.strict).set_dialect(dialect.clone()); if let Some(stepping) = dialect.stepping { diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 318a59912..8b48f99a8 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1573,5 +1573,8 @@ fn test_preprocess_can_recurse() { ]) .trim() .to_string(); - assert_eq!(res, "(2 (1 2 (3 5 (1 2 (1 18 5 (1 . 2)) 1) (1 2 (1 16 5 (1 . 1)) 1)) 1) (4 (1) 1))"); + assert_eq!( + res, + "(2 (1 2 (3 5 (1 2 (1 18 5 (1 . 2)) 1) (1 2 (1 16 5 (1 . 1)) 1)) 1) (4 (1) 1))" + ); } From 2a69fd4e435568b7a08712bb1f7e7c50c4f5b46b Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 17 Oct 2023 21:50:38 -0700 Subject: [PATCH 183/196] clippy --- src/compiler/preprocessor/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 8c3978f9e..605dd9b08 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -610,7 +610,7 @@ pub fn gather_dependencies( ) -> Result, CompileErr> { let mut allocator = Allocator::new(); - let assembled_input = assemble(&mut allocator, &file_content) + let assembled_input = assemble(&mut allocator, file_content) .map_err(|e| CompileErr(Srcloc::start(real_input_path), e.1))?; let dialect = detect_modern(&mut allocator, assembled_input); opts = opts.set_stdenv(dialect.strict).set_dialect(dialect.clone()); From d17d2a35799b2f300fe0f8b2f6686ed772a375b5 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 18 Oct 2023 10:03:43 -0700 Subject: [PATCH 184/196] fmt --- src/compiler/compiler.rs | 4 +- src/compiler/evaluate.rs | 1 - src/compiler/frontend.rs | 4 +- src/compiler/preprocessor/mod.rs | 67 +++++++++++++++----------------- src/tests/compiler/compiler.rs | 11 ++++-- 5 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 50f286536..6f2f26330 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -12,9 +12,7 @@ use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::compiler::clvm::sha256tree; use crate::compiler::codegen::{codegen, hoist_body_let_binding, process_helper_let_bindings}; -use crate::compiler::comptypes::{ - CompileErr, CompileForm, CompilerOpts, PrimaryCodegen, -}; +use crate::compiler::comptypes::{CompileErr, CompileForm, CompilerOpts, PrimaryCodegen}; use crate::compiler::dialect::{AcceptedDialect, KNOWN_DIALECTS}; use crate::compiler::frontend::frontend; use crate::compiler::optimize::get_optimizer; diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 7f4aa21b4..fab04f1e1 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -80,7 +80,6 @@ pub enum ArgInputs { Pair(Rc, Rc), } - /// Evaluator is an object that simplifies expressions, given the helpers /// (helpers are forms that are reusable parts of programs, such as defconst, /// defun or defmacro) from a program. In the simplest form, it can be used to diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 7c9dc2fd0..a2c1727bd 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -280,9 +280,7 @@ fn make_let_bindings( result.append(&mut rest_bindings); Ok(result) } - _ => { - err.clone() - } + _ => err.clone(), }) .unwrap_or_else(|| err.clone()), _ => err, diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 3e0f6b649..862bb4d44 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -302,39 +302,39 @@ impl Preprocessor { )?; let mut allocator = Allocator::new(); - let compiled_program = - if let Some(compiled_program) = self.stored_macros.get(&mdata.name) { - compiled_program.clone() - } else { - // as inline defuns because they're closest to that - // semantically. - let mut symbol_table = HashMap::new(); - let new_program = CompileForm { - loc: body.loc(), - args: mdata.args.clone(), - include_forms: vec![], - helpers: self.helpers.clone(), - exp: mdata.body.clone(), - }; - - let program_sexp = - Rc::new(SExp::Cons( - body.loc(), - Rc::new(SExp::Atom(body.loc(), b"mod".to_vec())), - new_program.to_sexp() - )); - - let compiled_program = self.opts.set_stdenv(false).compile_program( - &mut allocator, - self.runner.clone(), - program_sexp, - &mut symbol_table, - )?; - self.stored_macros - .insert(mdata.name.clone(), Rc::new(compiled_program.clone())); - Rc::new(compiled_program) + let compiled_program = if let Some(compiled_program) = + self.stored_macros.get(&mdata.name) + { + compiled_program.clone() + } else { + // as inline defuns because they're closest to that + // semantically. + let mut symbol_table = HashMap::new(); + let new_program = CompileForm { + loc: body.loc(), + args: mdata.args.clone(), + include_forms: vec![], + helpers: self.helpers.clone(), + exp: mdata.body.clone(), }; + let program_sexp = Rc::new(SExp::Cons( + body.loc(), + Rc::new(SExp::Atom(body.loc(), b"mod".to_vec())), + new_program.to_sexp(), + )); + + let compiled_program = self.opts.set_stdenv(false).compile_program( + &mut allocator, + self.runner.clone(), + program_sexp, + &mut symbol_table, + )?; + self.stored_macros + .insert(mdata.name.clone(), Rc::new(compiled_program.clone())); + Rc::new(compiled_program) + }; + let ppext: &PreprocessorExtension = self.ppext.borrow(); let res = clvm::run( &mut allocator, @@ -348,10 +348,7 @@ impl Preprocessor { .map(nilize) .map_err(CompileErr::from)?; - if let Some(final_result) = self.expand_macros( - res.clone(), - true, - )? { + if let Some(final_result) = self.expand_macros(res.clone(), true)? { return Ok(Some(final_result)); } else { return Ok(Some(res)); diff --git a/src/tests/compiler/compiler.rs b/src/tests/compiler/compiler.rs index e6ca97428..b43211a8d 100644 --- a/src/tests/compiler/compiler.rs +++ b/src/tests/compiler/compiler.rs @@ -6,8 +6,8 @@ use clvm_rs::allocator::Allocator; use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::compiler::clvm::run; use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; -use crate::compiler::dialect::AcceptedDialect; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; +use crate::compiler::dialect::AcceptedDialect; use crate::compiler::frontend::{collect_used_names_sexp, frontend}; use crate::compiler::rename::rename_in_cons; use crate::compiler::runtypes::RunFailure; @@ -264,8 +264,13 @@ fn run_test_4_opt() { } fn run_test_5_maybe_opt(opt: bool) { - let result = - run_string_maybe_opt(&"(mod (a) (list 1 2))".to_string(), &"()".to_string(), opt, false).unwrap(); + let result = run_string_maybe_opt( + &"(mod (a) (list 1 2))".to_string(), + &"()".to_string(), + opt, + false, + ) + .unwrap(); assert_eq!(result.to_string(), "(1 2)".to_string()); } From 78ec5a5e1b2d87cde50083158fd10080ee70c279 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 18 Oct 2023 10:24:25 -0700 Subject: [PATCH 185/196] Back out some stuff that's from the future --- src/compiler/comptypes.rs | 6 ----- src/compiler/preprocessor/mod.rs | 44 +++----------------------------- 2 files changed, 3 insertions(+), 47 deletions(-) diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 45014cbb2..8f5b2bb62 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -305,12 +305,6 @@ pub enum IncludeProcessType { Hex, /// Read clvm in s-expression form as a clvm value. SExpression, - /// Pointing to a chialisp program, Compiled specifies that we want - /// the compiled form of the program as a clvm value. It's possible - /// because chialisp programs self-identify how they're compiled and - /// the form they take is promised to be stable for released versions - /// of the language. - Compiled, } /// A description of an include form. Here, records the locations of the various diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index 862bb4d44..cc4f0b253 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -7,12 +7,11 @@ use std::rc::Rc; use clvmr::allocator::Allocator; use crate::classic::clvm_tools::binutils::assemble; -use crate::classic::clvm_tools::clvmc::compile_clvm_text_maybe_opt; use crate::classic::clvm_tools::stages::stage_0::{DefaultProgramRunner, TRunProgram}; use crate::compiler::cldb::hex_to_modern_sexp; use crate::compiler::clvm; -use crate::compiler::clvm::{convert_from_clvm_rs, truthy}; +use crate::compiler::clvm::truthy; use crate::compiler::comptypes::{ BodyForm, CompileErr, CompileForm, CompilerOpts, HelperForm, IncludeDesc, IncludeProcessType, }; @@ -182,23 +181,6 @@ impl Preprocessor { parsed[0].clone() } - IncludeProcessType::Compiled => { - let decoded_content = decode_string(&content); - let mut symtab = HashMap::new(); - let newly_compiled = compile_clvm_text_maybe_opt( - &mut allocator, - self.opts.optimize(), - self.opts.clone(), - &mut symtab, - &decoded_content, - &full_name, - true, - ) - .map_err(|e| CompileErr(loc.clone(), format!("Subcompile failed: {}", e.1)))?; - - convert_from_clvm_rs(&mut allocator, loc.clone(), newly_compiled) - .map_err(run_to_compile_err)? - } }; Ok(vec![compose_defconst(loc, constant_name, content)]) @@ -208,7 +190,6 @@ impl Preprocessor { fn recurse_dependencies( &mut self, includes: &mut Vec, - kind: IncludeProcessType, desc: IncludeDesc, ) -> Result<(), CompileErr> { let name_string = decode_string(&desc.name); @@ -222,10 +203,6 @@ impl Preprocessor { ..desc }); - if !matches!(kind, IncludeProcessType::Compiled) { - return Ok(()); - } - let parsed = parse_sexp(Srcloc::start(&full_name), content.iter().copied()) .map_err(|e| CompileErr(e.0, e.1))?; if parsed.is_empty() { @@ -452,21 +429,6 @@ impl Preprocessor { } } - [SExp::Atom(kl, compile_file), SExp::Atom(_, name), SExp::Atom(nl, fname)] => { - if compile_file == b"compile-file" { - return Ok(Some(IncludeType::Processed( - IncludeDesc { - kw: kl.clone(), - nl: nl.clone(), - kind: Some(IncludeProcessType::Compiled), - name: fname.clone(), - }, - IncludeProcessType::Compiled, - name.clone() - ))); - } - } - [SExp::Atom(kl, embed_file), SExp::Atom(_, name), SExp::Atom(_, kind), SExp::Atom(nl, fname)] => { if embed_file == b"embed-file" { if kind == b"hex" { @@ -540,10 +502,10 @@ impl Preprocessor { if let Some(()) = self.decode_macro(body.clone())? { Ok(vec![]) } else if let Some(IncludeType::Basic(i)) = &included { - self.recurse_dependencies(includes, IncludeProcessType::Compiled, i.clone())?; + self.recurse_dependencies(includes, i.clone())?; self.process_include(includes, i) } else if let Some(IncludeType::Processed(f, kind, name)) = &included { - self.recurse_dependencies(includes, kind.clone(), f.clone())?; + self.recurse_dependencies(includes, f.clone())?; self.process_embed(body.loc(), &decode_string(&f.name), kind, name) } else { Ok(vec![body]) From 53cbedceb860120bfc8cff913be677bd87b1e4c9 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 18 Oct 2023 10:27:58 -0700 Subject: [PATCH 186/196] Back out this change until it can be re-evaluated --- src/compiler/compiler.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 6f2f26330..04703f69c 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -127,12 +127,15 @@ pub fn desugar_pre_forms( do_desugar(&p1) } -pub fn compile_from_compileform( +pub fn compile_pre_forms( context: &mut BasicCompileContext, opts: Rc, - p0: CompileForm, + pre_forms: &[Rc], ) -> Result { - let p3 = context.post_desugar_optimization(opts.clone(), p0)?; + // Resolve includes, convert program source to lexemes + let p2 = desugar_pre_forms(context, opts.clone(), pre_forms)?; + + let p3 = context.post_desugar_optimization(opts.clone(), p2)?; // generate code from AST, optionally with optimization let generated = codegen(context, opts.clone(), &p3)?; @@ -142,17 +145,6 @@ pub fn compile_from_compileform( Ok(g2) } -pub fn compile_pre_forms( - context: &mut BasicCompileContext, - opts: Rc, - pre_forms: &[Rc], -) -> Result { - // Resolve includes, convert program source to lexemes - let p0 = desugar_pre_forms(context, opts.clone(), pre_forms)?; - - compile_from_compileform(context, opts, p0) -} - pub fn compile_file( allocator: &mut Allocator, runner: Rc, From 89ddca5272809b33e0b41e971ed992f24af14caa Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 18 Oct 2023 10:30:42 -0700 Subject: [PATCH 187/196] Back out artifacts from original evaluate based implementation --- src/compiler/evaluate.rs | 55 +++++++++++++++------------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index fab04f1e1..940b5fe92 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -19,7 +19,7 @@ use crate::compiler::comptypes::{ use crate::compiler::frontend::frontend; use crate::compiler::optimize::get_optimizer; use crate::compiler::runtypes::RunFailure; -use crate::compiler::sexp::{enlist, SExp}; +use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; use crate::compiler::stackvisit::{HasDepthLimit, VisitedMarker}; use crate::compiler::CompileContextWrapper; @@ -73,7 +73,6 @@ pub struct LambdaApply { // Frontend evaluator based on my fuzzer representation and direct interpreter of // that. - #[derive(Debug)] pub enum ArgInputs { Whole(Rc), @@ -347,7 +346,7 @@ fn decons_args(formed_tail: Rc) -> ArgInputs { } } -pub fn build_argument_captures( +fn build_argument_captures( l: &Srcloc, arguments_to_convert: &[Rc], tail: Option>, @@ -777,34 +776,6 @@ impl<'info> Evaluator { } } - fn defmac_ordering(&self) -> bool { - let dialect = self.opts.dialect(); - dialect.strict || dialect.stepping.unwrap_or(21) > 22 - } - - fn make_com_module(&self, l: &Srcloc, prog_args: Rc, body: Rc) -> Rc { - let end_of_list = if self.defmac_ordering() { - let mut mod_list: Vec> = self.helpers.iter().map(|h| h.to_sexp()).collect(); - mod_list.push(body); - Rc::new(enlist(l.clone(), &mod_list)) - } else { - let mut end_of_list = - Rc::new(SExp::Cons(l.clone(), body, Rc::new(SExp::Nil(l.clone())))); - - for h in self.helpers.iter() { - end_of_list = Rc::new(SExp::Cons(l.clone(), h.to_sexp(), end_of_list)); - } - - end_of_list - }; - - Rc::new(SExp::Cons( - l.clone(), - Rc::new(SExp::Atom(l.clone(), "mod".as_bytes().to_vec())), - Rc::new(SExp::Cons(l.clone(), prog_args, end_of_list)), - )) - } - fn is_lambda_apply( &self, allocator: &mut Allocator, @@ -915,9 +886,23 @@ impl<'info> Evaluator { prog_args, )))) } else if call.name == "com".as_bytes() { - let use_body = - self.make_com_module(&call.loc, prog_args, arguments_to_convert[0].to_sexp()); - let compiled = self.compile_code(allocator, false, use_body)?; + let mut end_of_list = Rc::new(SExp::Cons( + call.loc.clone(), + arguments_to_convert[0].to_sexp(), + Rc::new(SExp::Nil(call.loc.clone())), + )); + + for h in self.helpers.iter() { + end_of_list = Rc::new(SExp::Cons(call.loc.clone(), h.to_sexp(), end_of_list)) + } + + let use_body = SExp::Cons( + call.loc.clone(), + Rc::new(SExp::Atom(call.loc.clone(), "mod".as_bytes().to_vec())), + Rc::new(SExp::Cons(call.loc.clone(), prog_args, end_of_list)), + ); + + let compiled = self.compile_code(allocator, false, Rc::new(use_body))?; let compiled_borrowed: &SExp = compiled.borrow(); Ok(Rc::new(BodyForm::Quoted(compiled_borrowed.clone()))) } else { @@ -1657,7 +1642,7 @@ impl<'info> Evaluator { // primitive. let updated_opts = self .opts - .set_stdenv(!in_defun && !self.opts.dialect().strict) + .set_stdenv(!in_defun) .set_in_defun(in_defun) .set_frontend_opt(false); From 9181d184d935dd4d6efdabdecd98a805fd125401 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 18 Oct 2023 10:36:54 -0700 Subject: [PATCH 188/196] Back out further small changes that aren't needed --- src/classic/clvm_tools/clvmc.rs | 5 +++-- src/compiler/rename.rs | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/classic/clvm_tools/clvmc.rs b/src/classic/clvm_tools/clvmc.rs index 87f60e476..1ef267e4a 100644 --- a/src/classic/clvm_tools/clvmc.rs +++ b/src/classic/clvm_tools/clvmc.rs @@ -50,6 +50,7 @@ pub fn compile_clvm_text_maybe_opt( ) -> Result { let ir_src = read_ir(text).map_err(|s| EvalErr(allocator.null(), s.to_string()))?; let assembled_sexp = assemble_from_ir(allocator, Rc::new(ir_src))?; + let dialect = detect_modern(allocator, assembled_sexp); // Now the stepping is optional (None for classic) but we may communicate // other information in dialect as well. @@ -60,8 +61,8 @@ pub fn compile_clvm_text_maybe_opt( let runner = Rc::new(DefaultProgramRunner::new()); let opts = opts .set_dialect(dialect) - .set_optimize(do_optimize) - .set_frontend_opt(stepping > 21); + .set_optimize(do_optimize || stepping > 22) // Would apply to cl23 + .set_frontend_opt(stepping == 22); let unopt_res = compile_file(allocator, runner.clone(), opts.clone(), text, symbol_table); let res = unopt_res.and_then(|x| { diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index a43501b81..b88cbd638 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -207,15 +207,14 @@ fn rename_in_bodyform( &letdata.bindings, )?; let new_body = rename_in_bodyform(namemap, letdata.body.clone())?; - let res = BodyForm::Let( + Ok(BodyForm::Let( kind.clone(), Box::new(LetData { bindings: new_bindings, body: Rc::new(new_body), ..*letdata.clone() }), - ); - Ok(res) + )) } BodyForm::Quoted(atom) => match atom { From 482a5a971314762489d696b6f028555a2ff6c057 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 18 Oct 2023 14:19:11 -0700 Subject: [PATCH 189/196] Proper definitions of continued if --- src/compiler/compiler.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 04703f69c..bc5cde0cd 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -48,12 +48,12 @@ lazy_static! { (defun __chia__if (ARGS) (__chia__primitive__if (r (r (r ARGS))) - (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (unquote (__chia__if (r (r ARGS)))))) - (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS))))))) + (qq (a (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (__chia__if (r (r ARGS)))))) @)) + (qq (a (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS)))))) @)) ) ) - (defmac if ARGS (qq (a (unquote (__chia__if ARGS)) @))) + (defmac if ARGS (__chia__if ARGS)) (defun __chia__compile-list (args) (if args From c794430613d43100feac38757ac9d508f5592c97 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 18 Oct 2023 14:28:57 -0700 Subject: [PATCH 190/196] Test update --- src/tests/compiler/preprocessor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/compiler/preprocessor.rs b/src/tests/compiler/preprocessor.rs index cbd0d8821..e2a40e515 100644 --- a/src/tests/compiler/preprocessor.rs +++ b/src/tests/compiler/preprocessor.rs @@ -570,8 +570,8 @@ fn test_preprocessor_tours_includes_properly() { let res = preprocess(opts, &mut includes, parsed[0].clone()).expect("should preprocess"); let expected_lines = &[ "(defmac __chia__primitive__if (A B C) (qq (a (i (unquote A) (com (unquote B)) (com (unquote C))) @)))", - "(defun __chia__if (ARGS) (a (i (r (r (r ARGS))) (com (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (unquote (__chia__if (r (r ARGS))))))) (com (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS))))))))) @))", - "(defmac if ARGS (qq (a (unquote (__chia__if ARGS)) @)))", + "(defun __chia__if (ARGS) (a (i (r (r (r ARGS))) (com (qq (a (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (__chia__if (r (r ARGS)))))) @))) (com (qq (a (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS)))))) @)))) @))", + "(defmac if ARGS (__chia__if ARGS))", "(defun __chia__compile-list (args) (a (i args (com (c 4 (c (f args) (c (__chia__compile-list (r args)) ())))) (com ())) @))", "(defmac list ARGS (__chia__compile-list ARGS))", "(defun-inline / (A B) (f (divmod A B)))", From e996ec957dc0951e199cc551117499db63e5290e Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 19 Oct 2023 08:51:28 -0700 Subject: [PATCH 191/196] Simplify value kind testing functions, thanks to amine. --- src/compiler/preprocessor/macros.rs | 107 +++++++++++----------------- 1 file changed, 41 insertions(+), 66 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 2267018e4..f5ccb9f31 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -15,26 +15,22 @@ use crate::compiler::srcloc::Srcloc; use crate::util::{number_from_u8, Number}; // If the bodyform represents a constant, only match a quoted string. -fn match_quoted_string(body: Rc) -> Result)>, CompileErr> { - let is_string = match body.borrow() { - SExp::QuotedString(_, b'x', _) => None, - SExp::QuotedString(al, _, an) => Some((al.clone(), an.clone())), - _ => None, - }; - - if let Some((loc, s)) = is_string { - Ok(Some((loc, s))) - } else { - Err(CompileErr(body.loc(), "string required".to_string())) +fn match_quoted_string(body: Rc) -> Result<(Srcloc, Vec), CompileErr> { + match body.borrow() { + SExp::QuotedString(_, b'x', _) => {} + SExp::QuotedString(al, _, an) => return Ok((al.clone(), an.clone())), + _ => {} } + + Err(CompileErr(body.loc(), "string required".to_string())) } -fn match_atom(body: Rc) -> Result)>, CompileErr> { - if let SExp::Atom(al, an) = body.borrow() { - Ok(Some((al.clone(), an.clone()))) - } else { - Err(CompileErr(body.loc(), "atom required".to_string())) +fn match_atom(body: Rc) -> Result<(Srcloc, Vec), CompileErr> { + match body.borrow() { + SExp::Atom(al, an) => return Ok((al.clone(), an.clone())), + _ => {} } + Err(CompileErr(body.loc(), "atom required".to_string())) } enum MatchedNumber { @@ -42,35 +38,34 @@ enum MatchedNumber { MatchedHex(Srcloc, Vec), } -fn match_number(body: Rc) -> Result, CompileErr> { +fn match_number(body: Rc) -> Result { match body.borrow() { SExp::Integer(il, n) => { - return Ok(Some(MatchedNumber::MatchedInt(il.clone(), n.clone()))); + return Ok(MatchedNumber::MatchedInt(il.clone(), n.clone())); } SExp::QuotedString(ql, b'x', b) => { - return Ok(Some(MatchedNumber::MatchedHex(ql.clone(), b.clone()))); + return Ok(MatchedNumber::MatchedHex(ql.clone(), b.clone())); } SExp::Atom(al, b) => { // An atom with unprintable characters is rendered as an integer. if !printable(b) { let to_integer = number_from_u8(b); - return Ok(Some(MatchedNumber::MatchedInt(al.clone(), to_integer))); + return Ok(MatchedNumber::MatchedInt(al.clone(), to_integer)); } } SExp::Nil(il) => { - return Ok(Some(MatchedNumber::MatchedInt(il.clone(), bi_zero()))); + return Ok(MatchedNumber::MatchedInt(il.clone(), bi_zero())); } _ => {} } - Err(CompileErr(body.loc(), "number required".to_string())) + Err(CompileErr(body.loc(), "Not a number".to_string())) } fn numeric_value(body: Rc) -> Result { match match_number(body.clone())? { - Some(MatchedNumber::MatchedInt(_, n)) => Ok(n), - Some(MatchedNumber::MatchedHex(_, h)) => Ok(number_from_u8(&h)), - _ => Err(CompileErr(body.loc(), "Not a number".to_string())), + MatchedNumber::MatchedInt(_, n) => Ok(n), + MatchedNumber::MatchedHex(_, h) => Ok(number_from_u8(&h)), } } @@ -112,7 +107,7 @@ impl ExtensionFunction for StringQ { fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let res = match match_quoted_string(args[0].clone()) { - Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), + Ok(_) => SExp::Integer(loc.clone(), bi_one()), _ => SExp::Nil(loc.clone()), }; @@ -135,7 +130,7 @@ impl ExtensionFunction for NumberQ { fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let res = match match_number(args[0].clone()) { - Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), + Ok(_) => SExp::Integer(loc.clone(), bi_one()), _ => SExp::Nil(loc.clone()), }; @@ -158,7 +153,7 @@ impl ExtensionFunction for SymbolQ { fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let res = match match_atom(args[0].clone()) { - Ok(Some(_)) => SExp::Integer(loc.clone(), bi_one()), + Ok(_) => SExp::Integer(loc.clone(), bi_one()), _ => SExp::Nil(loc.clone()), }; @@ -180,11 +175,8 @@ impl ExtensionFunction for SymbolToString { } fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { - if let Some((loc, value)) = match_atom(args[0].clone())? { - Ok(Rc::new(SExp::QuotedString(loc, b'\"', value))) - } else { - Err(CompileErr(args[0].loc(), "Not a symbol".to_string())) - } + let (loc, value) = match_atom(args[0].clone())?; + Ok(Rc::new(SExp::QuotedString(loc, b'\"', value))) } } @@ -202,11 +194,8 @@ impl ExtensionFunction for StringToSymbol { } fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { - if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - Ok(Rc::new(SExp::Atom(loc, value))) - } else { - Err(CompileErr(args[0].loc(), "Not a string".to_string())) - } + let (loc, value) = match_quoted_string(args[0].clone())?; + Ok(Rc::new(SExp::Atom(loc, value))) } } @@ -227,14 +216,11 @@ impl ExtensionFunction for StringAppend { let mut out_vec = Vec::new(); let mut out_loc = None; for a in args.iter() { - if let Some((loc, mut value)) = match_quoted_string(a.clone())? { - if out_loc.is_none() { - out_loc = Some(loc); - } - out_vec.append(&mut value); - } else { - return Err(CompileErr(a.loc(), "not a quoted string".to_string())); + let (loc, mut value) = match_quoted_string(a.clone())?; + if out_loc.is_none() { + out_loc = Some(loc); } + out_vec.append(&mut value); } Ok(Rc::new(SExp::QuotedString( out_loc.unwrap_or_else(|| loc.clone()), @@ -260,11 +246,8 @@ impl ExtensionFunction for NumberToString { fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { let match_res = match_number(args[0].clone())?; let (use_loc, int_val) = match &match_res { - Some(MatchedNumber::MatchedInt(l, i)) => (l.clone(), i.clone()), - Some(MatchedNumber::MatchedHex(l, h)) => (l.clone(), number_from_u8(h)), - _ => { - return Err(CompileErr(args[0].loc(), "Not a number".to_string())); - } + MatchedNumber::MatchedInt(l, i) => (l.clone(), i.clone()), + MatchedNumber::MatchedHex(l, h) => (l.clone(), number_from_u8(h)), }; Ok(Rc::new(SExp::QuotedString( use_loc, @@ -287,18 +270,12 @@ impl ExtensionFunction for StringToNumber { Some(1) } - fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { - if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - if let Ok(cvt_bi) = decode_string(&value).parse::() { - Ok(Rc::new(SExp::Integer(loc, cvt_bi))) - } else { - Err(CompileErr(loc, "bad number".to_string())) - } + fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { + let (loc, value) = match_quoted_string(args[0].clone())?; + if let Ok(cvt_bi) = decode_string(&value).parse::() { + Ok(Rc::new(SExp::Integer(loc, cvt_bi))) } else { - Err(CompileErr( - loc.clone(), - "should be given a string".to_string(), - )) + Err(CompileErr(loc, "bad number".to_string())) } } } @@ -317,12 +294,10 @@ impl ExtensionFunction for StringLength { } fn try_eval(&self, _loc: &Srcloc, args: &[Rc]) -> Result, CompileErr> { - if let Some((loc, value)) = match_quoted_string(args[0].clone())? { - if let Some(len_bi) = value.len().to_bigint() { - return Ok(Rc::new(SExp::Integer(loc, len_bi))); - } + let (loc, value) = match_quoted_string(args[0].clone())?; + if let Some(len_bi) = value.len().to_bigint() { + return Ok(Rc::new(SExp::Integer(loc, len_bi))); } - Err(CompileErr( args[0].loc(), "Error getting string length".to_string(), From 5efb7a984ad3da04a7cc2e2ce8fe58cf75768449 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 19 Oct 2023 09:14:23 -0700 Subject: [PATCH 192/196] fmt + clippy --- src/compiler/preprocessor/macros.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index f5ccb9f31..2064371df 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -26,9 +26,8 @@ fn match_quoted_string(body: Rc) -> Result<(Srcloc, Vec), CompileErr> } fn match_atom(body: Rc) -> Result<(Srcloc, Vec), CompileErr> { - match body.borrow() { - SExp::Atom(al, an) => return Ok((al.clone(), an.clone())), - _ => {} + if let SExp::Atom(al, an) = body.borrow() { + return Ok((al.clone(), an.clone())); } Err(CompileErr(body.loc(), "atom required".to_string())) } From 09b7d9837dcd8dd59783535a48c284def527f6f7 Mon Sep 17 00:00:00 2001 From: Earle Lowe Date: Fri, 20 Oct 2023 09:30:52 -0700 Subject: [PATCH 193/196] Add riscv build and test workflow --- .github/workflows/build-riscv.yml | 81 +++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 .github/workflows/build-riscv.yml diff --git a/.github/workflows/build-riscv.yml b/.github/workflows/build-riscv.yml new file mode 100644 index 000000000..d7b0d32fe --- /dev/null +++ b/.github/workflows/build-riscv.yml @@ -0,0 +1,81 @@ +name: QEMU Build and test riscv64 crate + +on: + push: + branches: + - main + - dev + tags: + - '**' + pull_request: + branches: + - '**' + +jobs: + build_crate: + name: Build riscv64 crate and run tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 1 + + - name: Set up QEMU on x86_64 + id: qemu + uses: docker/setup-qemu-action@v2 + with: + platforms: riscv64 + + - name: Build and Test + run: | + docker run --rm --platform linux/riscv64 \ + -v ${{ github.workspace }}:/ws --workdir=/ws \ + chianetwork/ubuntu-22.04-risc-builder:latest \ + bash -exc '\ + cargo test --release + ' + + build_wheels: + name: QEMU riscv64 wheel + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 1 + + - name: Set up QEMU on x86_64 + id: qemu + uses: docker/setup-qemu-action@v2 + with: + platforms: riscv64 + + - name: Build + run: | + docker run --rm --platform linux/riscv64 \ + -v ${{ github.workspace }}:/ws --workdir=/ws \ + chianetwork/ubuntu-22.04-risc-builder:latest \ + bash -exc '\ + pyenv global 3.10 + python -m venv venv && \ + source ./venv/bin/activate && \ + pip install --upgrade pip && \ + pip install --extra-index-url https://pypi.chia.net/simple/ maturin==1.2.3 && \ + maturin build -i python --release --strip \ + ' + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: packages + path: ./wheel/target/wheels/ + From 2ee4a3b347a49380d589c0fd1651ba189bd0284f Mon Sep 17 00:00:00 2001 From: Earle Lowe <30607889+emlowe@users.noreply.github.com> Date: Mon, 23 Oct 2023 07:30:23 -0700 Subject: [PATCH 194/196] fix upload path --- .github/workflows/build-riscv.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-riscv.yml b/.github/workflows/build-riscv.yml index d7b0d32fe..7fef28d9d 100644 --- a/.github/workflows/build-riscv.yml +++ b/.github/workflows/build-riscv.yml @@ -77,5 +77,5 @@ jobs: uses: actions/upload-artifact@v3 with: name: packages - path: ./wheel/target/wheels/ + path: ./target/wheels/ From ba0035ad4f00f11465ff9d294cf60140a5495cbe Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 24 Oct 2023 06:14:21 -0700 Subject: [PATCH 195/196] Take some code shortenings from amine --- src/compiler/codegen.rs | 30 ++++++----------- src/compiler/preprocessor/macros.rs | 52 ++++++++++++----------------- src/compiler/preprocessor/mod.rs | 10 ++---- src/compiler/runtypes.rs | 8 +++++ src/compiler/sexp.rs | 4 +-- 5 files changed, 44 insertions(+), 60 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 589cecaf1..8267a4964 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -700,28 +700,20 @@ pub fn generate_expr_code( // strict mode closes the necessary loophole below. Values // intended as variable names are never crushed into integer // like values from modern macros. - if opts.dialect().strict { - return generate_expr_code( - context, - opts, - compiler, - Rc::new(BodyForm::Quoted(SExp::Integer(l.clone(), i.clone()))), - ); - } - - // Since macros are in this language and the runtime has - // a very narrow data representation, we'll need to - // accomodate bare numbers coming back in place of identifiers, - // but only in legacy non-strict mode. - generate_expr_code( - context, - opts, - compiler, + let ambiguous_int_value = if opts.dialect().strict { + Rc::new(BodyForm::Quoted(SExp::Integer(l.clone(), i.clone()))) + } else { + // Since macros are in this language and the runtime has + // a very narrow data representation, we'll need to + // accomodate bare numbers coming back in place of identifiers, + // but only in legacy non-strict mode. Rc::new(BodyForm::Value(SExp::Atom( l.clone(), u8_from_number(i.clone()), - ))), - ) + ))) + }; + + generate_expr_code(context, opts, compiler, ambiguous_int_value) } _ => Ok(CompiledCode( v.loc(), diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 2064371df..68a0c0b0d 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -87,15 +87,14 @@ pub trait ExtensionFunction { true } fn required_args(&self) -> Option; - #[allow(clippy::too_many_arguments)] fn try_eval(&self, loc: &Srcloc, args: &[Rc]) -> Result, CompileErr>; } -struct StringQ {} +struct StringQ; impl StringQ { fn create() -> Rc { - Rc::new(StringQ {}) + Rc::new(StringQ) } } @@ -114,11 +113,11 @@ impl ExtensionFunction for StringQ { } } -struct NumberQ {} +struct NumberQ; impl NumberQ { fn create() -> Rc { - Rc::new(NumberQ {}) + Rc::new(NumberQ) } } @@ -137,11 +136,11 @@ impl ExtensionFunction for NumberQ { } } -struct SymbolQ {} +struct SymbolQ; impl SymbolQ { fn create() -> Rc { - Rc::new(SymbolQ {}) + Rc::new(SymbolQ) } } @@ -160,11 +159,11 @@ impl ExtensionFunction for SymbolQ { } } -struct SymbolToString {} +struct SymbolToString; impl SymbolToString { fn create() -> Rc { - Rc::new(SymbolToString {}) + Rc::new(SymbolToString) } } @@ -179,11 +178,11 @@ impl ExtensionFunction for SymbolToString { } } -struct StringToSymbol {} +struct StringToSymbol; impl StringToSymbol { fn create() -> Rc { - Rc::new(StringToSymbol {}) + Rc::new(StringToSymbol) } } @@ -198,11 +197,11 @@ impl ExtensionFunction for StringToSymbol { } } -struct StringAppend {} +struct StringAppend; impl StringAppend { fn create() -> Rc { - Rc::new(StringAppend {}) + Rc::new(StringAppend) } } @@ -229,11 +228,11 @@ impl ExtensionFunction for StringAppend { } } -struct NumberToString {} +struct NumberToString; impl NumberToString { fn create() -> Rc { - Rc::new(NumberToString {}) + Rc::new(NumberToString) } } @@ -256,11 +255,11 @@ impl ExtensionFunction for NumberToString { } } -struct StringToNumber {} +struct StringToNumber; impl StringToNumber { fn create() -> Rc { - Rc::new(StringToNumber {}) + Rc::new(StringToNumber) } } @@ -279,11 +278,11 @@ impl ExtensionFunction for StringToNumber { } } -struct StringLength {} +struct StringLength; impl StringLength { fn create() -> Rc { - Rc::new(StringLength {}) + Rc::new(StringLength) } } @@ -304,11 +303,11 @@ impl ExtensionFunction for StringLength { } } -struct Substring {} +struct Substring; impl Substring { fn create() -> Rc { - Rc::new(Substring {}) + Rc::new(Substring) } } @@ -380,12 +379,6 @@ pub struct PreprocessorExtension { extfuns: HashMap, Rc>, } -fn compile_to_run_err(e: CompileErr) -> RunFailure { - match e { - CompileErr(l, e) => RunFailure::RunErr(l, e), - } -} - impl PrimOverride for PreprocessorExtension { fn try_handle( &self, @@ -401,10 +394,7 @@ impl PrimOverride for PreprocessorExtension { }; if let Some(extension) = self.extfuns.get(head_atom) { - let res = extension - .try_eval(hl, &have_args) - .map_err(compile_to_run_err)?; - + let res = extension.try_eval(hl, &have_args)?; return Ok(Some(res)); } } diff --git a/src/compiler/preprocessor/mod.rs b/src/compiler/preprocessor/mod.rs index cc4f0b253..69fadd9dc 100644 --- a/src/compiler/preprocessor/mod.rs +++ b/src/compiler/preprocessor/mod.rs @@ -253,9 +253,8 @@ impl Preprocessor { return Ok(new_self); } - if let Ok(NodeSel::Cons((_, name), args)) = - NodeSel::Cons(Atom::Here(()), ThisNode::Here) - .select_nodes(new_self.clone().unwrap_or_else(|| body.clone())) + if let Ok(NodeSel::Cons((_, name), args)) = NodeSel::Cons(Atom::Here(()), ThisNode) + .select_nodes(new_self.clone().unwrap_or_else(|| body.clone())) { let defmac_name = make_defmac_name(&name); @@ -347,10 +346,7 @@ impl Preprocessor { NodeSel::Cons((nl, name), NodeSel::Cons(args, body)), )) = NodeSel::Cons( Atom::Here(()), - NodeSel::Cons( - Atom::Here(()), - NodeSel::Cons(ThisNode::Here, ThisNode::Here), - ), + NodeSel::Cons(Atom::Here(()), NodeSel::Cons(ThisNode, ThisNode)), ) .select_nodes(definition.clone()) { diff --git a/src/compiler/runtypes.rs b/src/compiler/runtypes.rs index c19d5cc45..526f9afef 100644 --- a/src/compiler/runtypes.rs +++ b/src/compiler/runtypes.rs @@ -37,3 +37,11 @@ impl From for CompileErr { } } } + +impl From for RunFailure { + fn from(e: CompileErr) -> Self { + match e { + CompileErr(l, e) => RunFailure::RunErr(l, e), + } + } +} diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 605bf48d0..30becac44 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -1007,9 +1007,7 @@ pub enum Rest { } #[derive(Debug, Clone)] -pub enum ThisNode { - Here, -} +pub struct ThisNode; pub enum Atom { Here(T), From 619d6d49dc791b7a561a623255ad30d37d4a56bb Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 24 Oct 2023 09:03:49 -0700 Subject: [PATCH 196/196] Add renames that were needed but missed downstream of assign --- resources/tests/cse-complex-21.clsp | 28 ++++++++++++++++++++++++++++ src/compiler/rename.rs | 9 ++++++--- src/tests/classic/run.rs | 22 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 resources/tests/cse-complex-21.clsp diff --git a/resources/tests/cse-complex-21.clsp b/resources/tests/cse-complex-21.clsp new file mode 100644 index 000000000..531bb5c41 --- /dev/null +++ b/resources/tests/cse-complex-21.clsp @@ -0,0 +1,28 @@ +(mod (X) + (include *standard-cl-21*) + + (defun mess (X) ;; 11 41 + (assign + Y (+ X 1) ;; 12 42 + Z (+ Y 2) ;; 14 44 + + (if (= X 11) + (assign + Y (* X 2) ;; 22 82 + Z (+ Y 1) ;; 23 83 + + (* Y Z) ;; 22 * 23 = 506 + ) + + (assign + Y (* X 3) ;; 33 123 + Z (+ Y 2) ;; 35 125 + + (* Y Z) ;; 123 * 125 = 15375 + ) + ) + ) + ) + + (mess X) + ) diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 40ad2e0b8..30557c681 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -164,7 +164,7 @@ pub fn rename_assign_bindings( ) -> Result<(BodyForm, Vec>), CompileErr> { // Order the bindings. let sorted_bindings = toposort_assign_bindings(l, bindings)?; - let mut renames = HashMap::new(); + let mut renames: HashMap, Vec> = HashMap::new(); // Process in reverse order so we rename from inner to outer. let bindings_to_rename: Vec> = sorted_bindings.to_vec(); let renamed_bindings = map_m_reverse( @@ -175,9 +175,11 @@ pub fn rename_assign_bindings( for (name, renamed) in new_names.iter() { renames.insert(name.clone(), renamed.clone()); } + + let renamed_in_body = Rc::new(rename_args_bodyform(b.body.borrow())?); Ok(Rc::new(Binding { pattern: BindingPattern::Complex(rename_in_cons(&renames, p.clone(), false)), - body: Rc::new(rename_in_bodyform(&renames, b.body.clone())?), + body: Rc::new(rename_in_bodyform(&renames, renamed_in_body)?), ..b.clone() })) } else { @@ -186,7 +188,8 @@ pub fn rename_assign_bindings( }, &bindings_to_rename, )?; - Ok((rename_in_bodyform(&renames, body)?, renamed_bindings)) + let new_body = Rc::new(rename_args_bodyform(body.borrow())?); + Ok((rename_in_bodyform(&renames, new_body)?, renamed_bindings)) } fn rename_in_bodyform( diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index b7f038fc1..69e8f297e 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1343,3 +1343,25 @@ fn test_classic_obeys_operator_choice_at_compile_time_version_0() { .to_string(); assert_eq!(compiled, "FAIL: unimplemented operator 48"); } + +#[test] +fn test_assign_rename_tricky() { + let filename = "resources/tests/cse-complex-21.clsp"; + let program = do_basic_run(&vec!["run".to_string(), filename.to_string()]) + .trim() + .to_string(); + + let run_result_11 = do_basic_brun(&vec![ + "brun".to_string(), + program.clone(), + "(11)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(run_result_11, "506"); + + let run_result_41 = do_basic_brun(&vec!["brun".to_string(), program, "(41)".to_string()]) + .trim() + .to_string(); + assert_eq!(run_result_41, "15375"); +}