From b17048d68ac6b5557589e8fd66fbc269167b0917 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 4 Jul 2024 18:30:47 -0700 Subject: [PATCH 1/8] More elegant parsing, make an object of the common outputs --- src/classic/clvm_tools/cmds.rs | 269 +++++++++++++++++---------------- 1 file changed, 140 insertions(+), 129 deletions(-) diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 21a2dcc5d..b502c6ec1 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -496,6 +496,82 @@ pub fn cldb_hierarchy( result } +fn get_string_and_filename_with_default( + parsed_args: &HashMap, + argument: &str, + default: Option<&str>, +) -> Option<(Option, String)> { + if let Some(ArgumentValue::ArgString(path, content)) = parsed_args.get(argument) { + Some((path.clone(), content.to_string())) + } else { + default.map(|p| (None, p.to_string())) + } +} + +struct ParsedInputPathOrCode { + path: Option, + content: String, + parsed: NodePtr, +} + +fn parse_tool_input_sexp( + allocator: &mut Allocator, + argument: &str, + parsed_args: &HashMap, + default_hex: Option<&str>, + default_sexp: Option<&str>, +) -> Result { + match parsed_args.get("hex") { + Some(_) => { + let (path, use_sexp_text) = if let Some(r) = + get_string_and_filename_with_default(parsed_args, argument, default_hex) + { + r + } else { + return Err("missing argument {argument}".to_string()); + }; + + let sexp_serialized = + Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(use_sexp_text.clone()))) + .map_err(|e| format!("{e:?}"))?; + + let mut prog_stream = Stream::new(Some(sexp_serialized)); + + sexp_from_stream( + allocator, + &mut prog_stream, + Box::new(SimpleCreateCLVMObject {}), + ) + .map(|x| ParsedInputPathOrCode { + path, + content: use_sexp_text, + parsed: x.1, + }) + .map_err(|e| format!("{e:?}")) + } + _ => { + let (path, use_sexp_text) = if let Some(r) = + get_string_and_filename_with_default(parsed_args, argument, default_sexp) + { + r + } else { + return Err(format!("missing argument {argument}")); + }; + + read_ir(&use_sexp_text) + .map_err(|e| format!("{e:?}")) + .and_then(|v| { + Ok(ParsedInputPathOrCode { + path, + content: use_sexp_text, + parsed: assemble_from_ir(allocator, Rc::new(v)) + .map_err(|e| format!("{e:?}"))?, + }) + }) + } + } +} + pub fn cldb(args: &[String]) { let tool_name = "cldb".to_string(); let props = TArgumentParserProps { @@ -558,14 +634,10 @@ pub fn cldb(args: &[String]) { ); let arg_vec = args[1..].to_vec(); - let mut input_file = None; - let mut input_program = "()".to_string(); - let prog_srcloc = Srcloc::start("*program*"); let args_srcloc = Srcloc::start("*args*"); let mut args = Rc::new(sexp::SExp::atom_from_string(args_srcloc.clone(), "")); - let mut parsed_args_result: String = "".to_string(); let parsed_args: HashMap = match parser.parse_args(&arg_vec) { Err(e) => { @@ -583,16 +655,40 @@ pub fn cldb(args: &[String]) { } } - if let Some(ArgumentValue::ArgString(file, path_or_code)) = parsed_args.get("path_or_code") { - input_file.clone_from(file); - input_program = path_or_code.to_string(); - } + let mut allocator = Allocator::new(); + let mut output = Vec::new(); - if let Some(ArgumentValue::ArgString(_, s)) = parsed_args.get("env") { - parsed_args_result = s.to_string(); - } + let errorize = + |output: &mut Vec>, location: Option, c: &str| { + let mut parse_error = BTreeMap::new(); + if let Some(l) = location { + parse_error.insert( + "Error-Location".to_string(), + YamlElement::String(l.to_string()), + ); + }; + parse_error.insert("Error".to_string(), YamlElement::String(c.to_string())); + output.push(parse_error.clone()); + println!("{}", yamlette_string(output)); + }; - let mut allocator = Allocator::new(); + let parsed_program_result = + match parse_tool_input_sexp(&mut allocator, "path_or_code", &parsed_args, None, None) { + Ok(r) => r, + Err(e) => { + errorize(&mut output, None, &e.to_string()); + return; + } + }; + + let parsed_args_result = + match parse_tool_input_sexp(&mut allocator, "env", &parsed_args, Some("80"), Some("()")) { + Ok(r) => r, + Err(e) => { + errorize(&mut output, None, &e.to_string()); + return; + } + }; let symbol_table = parsed_args .get("symbol_table") @@ -612,7 +708,8 @@ pub fn cldb(args: &[String]) { .map(|x| matches!(x, ArgumentValue::ArgBool(true))) .unwrap_or_else(|| false); let runner = Rc::new(DefaultProgramRunner::new()); - let use_filename = input_file + let use_filename = parsed_program_result + .path .clone() .unwrap_or_else(|| "*command*".to_string()); let opts = Rc::new(DefaultCompilerOpts::new(&use_filename)) @@ -620,14 +717,13 @@ pub fn cldb(args: &[String]) { .set_search_paths(&search_paths); let mut use_symbol_table = symbol_table.unwrap_or_default(); - let mut output = Vec::new(); let res = match parsed_args.get("hex") { Some(ArgumentValue::ArgBool(true)) => hex_to_modern_sexp( &mut allocator, &use_symbol_table, prog_srcloc.clone(), - &input_program, + &parsed_program_result.content, ) .map_err(|_| CompileErr(prog_srcloc, "Failed to parse hex".to_string())), _ => { @@ -637,7 +733,7 @@ pub fn cldb(args: &[String]) { &mut allocator, runner.clone(), opts.clone(), - &input_program, + &parsed_program_result.content, &mut use_symbol_table, ); unopt_res.and_then(|x| { @@ -655,14 +751,7 @@ pub fn cldb(args: &[String]) { let program = match res { Ok(r) => r, Err(c) => { - let mut parse_error = BTreeMap::new(); - parse_error.insert( - "Error-Location".to_string(), - YamlElement::String(c.0.to_string()), - ); - parse_error.insert("Error".to_string(), YamlElement::String(c.1)); - output.push(parse_error.clone()); - println!("{}", yamlette_string(&output)); + errorize(&mut output, Some(c.0.clone()), &c.1); return; } }; @@ -673,7 +762,7 @@ pub fn cldb(args: &[String]) { &mut allocator, &HashMap::new(), args_srcloc, - &parsed_args_result, + &parsed_args_result.content, ) { Ok(r) => { args = r; @@ -687,7 +776,7 @@ pub fn cldb(args: &[String]) { } } } - _ => match parse_sexp(Srcloc::start("*arg*"), parsed_args_result.bytes()) { + _ => match parse_sexp(Srcloc::start("*arg*"), parsed_args_result.content.bytes()) { Ok(r) => { if !r.is_empty() { args = r[0].clone(); @@ -711,10 +800,15 @@ pub fn cldb(args: &[String]) { for p in prims::prims().iter() { prim_map.insert(p.0.clone(), Rc::new(p.1.clone())); } - let program_lines: Rc> = - Rc::new(input_program.lines().map(|x| x.to_string()).collect()); + let program_lines: Rc> = Rc::new( + parsed_program_result + .content + .lines() + .map(|x| x.to_string()) + .collect(), + ); let cldbenv = CldbRunEnv::new( - input_file.clone(), + parsed_program_result.path.clone(), program_lines.clone(), Box::new(CldbNoOverride::new_symbols(use_symbol_table.clone())), ); @@ -723,7 +817,7 @@ pub fn cldb(args: &[String]) { let result = cldb_hierarchy( runner, Rc::new(prim_map), - input_file, + parsed_program_result.path.clone(), program_lines, Rc::new(use_symbol_table), program, @@ -1142,14 +1236,8 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let mut allocator = Allocator::new(); - let input_serialized = None; - let mut input_sexp: Option = None; - let time_start = SystemTime::now(); - let mut time_read_hex = SystemTime::now(); - let mut time_assemble = SystemTime::now(); - - let mut input_args = "()".to_string(); + let time_read_hex = SystemTime::now(); if let ( Some(ArgumentValue::ArgBool(true)), @@ -1178,11 +1266,6 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul return; } - if let Some(ArgumentValue::ArgString(file, path_or_code)) = parsed_args.get("env") { - input_file.clone_from(file); - input_args = path_or_code.to_string(); - } - let special_runner = run_program_for_search_paths(&reported_input_file, &search_paths, extra_symbol_info); // Ensure we know the user's wishes about the disassembly version here. @@ -1190,88 +1273,26 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let dpr = special_runner.clone(); let run_program = special_runner; - match parsed_args.get("hex") { - Some(_) => { - let assembled_serialized = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex( - input_program.to_string(), - ))); - - let env_serialized = if input_args.is_empty() { - Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex("80".to_string()))) - } else { - Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(input_args))) - }; - - let ee = match env_serialized { - Ok(x) => x, - Err(e) => { - stdout.write_str(&format!("FAIL: {e}\n")); - return; - } - }; - time_read_hex = SystemTime::now(); - - let mut prog_stream = Stream::new(Some(match assembled_serialized { - Ok(x) => x, - Err(e) => { - stdout.write_str(&format!("FAIL: {e}\n")); - return; - } - })); - - let input_prog_sexp = sexp_from_stream( - &mut allocator, - &mut prog_stream, - Box::new(SimpleCreateCLVMObject {}), - ) - .map(|x| Some(x.1)) - .unwrap(); - - let mut arg_stream = Stream::new(Some(ee)); - let input_arg_sexp = sexp_from_stream( - &mut allocator, - &mut arg_stream, - Box::new(SimpleCreateCLVMObject {}), - ) - .map(|x| Some(x.1)) - .unwrap(); - if let (Some(ip), Some(ia)) = (input_prog_sexp, input_arg_sexp) { - input_sexp = allocator.new_pair(ip, ia).ok(); - } - } - _ => { - let src_sexp; - if let Some(ArgumentValue::ArgString(f, content)) = parsed_args.get("path_or_code") { - match read_ir(content) { - Ok(s) => { - input_program.clone_from(content); - input_file.clone_from(f); - src_sexp = s; - } - Err(e) => { - stdout.write_str(&format!("FAIL: {e}\n")); - return; - } - } - } else { - stdout.write_str(&format!("FAIL: {}\n", "non-string argument")); + let assembled_sexp = + match parse_tool_input_sexp(&mut allocator, "path_or_code", &parsed_args, None, None) { + Ok(s) => s, + Err(e) => { + stdout.write_str(&format!("FAIL: {e}\n")); return; } + }; - let assembled_sexp = assemble_from_ir(&mut allocator, Rc::new(src_sexp)).unwrap(); - let mut parsed_args_result = "()".to_string(); - - if let Some(ArgumentValue::ArgString(_f, s)) = parsed_args.get("env") { - parsed_args_result = s.to_string(); - } + let env = match parse_tool_input_sexp(&mut allocator, "env", &parsed_args, None, None) { + Ok(s) => s, + Err(e) => { + stdout.write_str(&format!("FAIL: {e}\n")); + return; + } + }; - let env_ir = read_ir(&parsed_args_result).unwrap(); - let env = assemble_from_ir(&mut allocator, Rc::new(env_ir)).unwrap(); - time_assemble = SystemTime::now(); + let time_assemble = SystemTime::now(); - input_sexp = allocator.new_pair(assembled_sexp, env).ok(); - } - } + let input_sexp = allocator.new_pair(assembled_sexp.parsed, env.parsed).ok(); // Symbol table related checks: should one be loaded, should one be saved. // This code is confusingly woven due to 'run' and 'brun' serving many roles. @@ -1488,16 +1509,6 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .unwrap_or_else(|| 0); let max_cost = max(0, max_cost); - if input_sexp.is_none() { - input_sexp = sexp_from_stream( - &mut allocator, - &mut Stream::new(input_serialized), - Box::new(SimpleCreateCLVMObject {}), - ) - .map(|x| Some(x.1)) - .unwrap(); - }; - // Part 2 of doing pre_eval: Have a thing that receives the messages and // performs some action. let log_entries_clone = log_entries.clone(); From 3d05a623c789f0ef50a09a40f2760a88ff6928e5 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 5 Jul 2024 11:34:13 -0700 Subject: [PATCH 2/8] Break out all determination of dialect into something common between cldb and run --- src/classic/clvm_tools/cmds.rs | 136 +++++---------------------- src/classic/clvm_tools/comp_input.rs | 126 +++++++++++++++++++++++++ src/classic/clvm_tools/mod.rs | 1 + 3 files changed, 151 insertions(+), 112 deletions(-) create mode 100644 src/classic/clvm_tools/comp_input.rs diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index b502c6ec1..d2dd0c816 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -30,6 +30,7 @@ use crate::classic::clvm::sexp::{enlist, proper_list, sexp_as_bin}; use crate::classic::clvm::OPERATORS_LATEST_VERSION; use crate::classic::clvm_tools::binutils::{assemble_from_ir, disassemble, disassemble_with_kw}; use crate::classic::clvm_tools::clvmc::write_sym_output; +use crate::classic::clvm_tools::comp_input::RunAndCompileInputData; 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, @@ -55,7 +56,6 @@ 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::dialect::detect_modern; use crate::compiler::frontend::frontend; use crate::compiler::optimize::maybe_finalize_program_via_classic_optimizer; use crate::compiler::preprocessor::gather_dependencies; @@ -496,82 +496,6 @@ pub fn cldb_hierarchy( result } -fn get_string_and_filename_with_default( - parsed_args: &HashMap, - argument: &str, - default: Option<&str>, -) -> Option<(Option, String)> { - if let Some(ArgumentValue::ArgString(path, content)) = parsed_args.get(argument) { - Some((path.clone(), content.to_string())) - } else { - default.map(|p| (None, p.to_string())) - } -} - -struct ParsedInputPathOrCode { - path: Option, - content: String, - parsed: NodePtr, -} - -fn parse_tool_input_sexp( - allocator: &mut Allocator, - argument: &str, - parsed_args: &HashMap, - default_hex: Option<&str>, - default_sexp: Option<&str>, -) -> Result { - match parsed_args.get("hex") { - Some(_) => { - let (path, use_sexp_text) = if let Some(r) = - get_string_and_filename_with_default(parsed_args, argument, default_hex) - { - r - } else { - return Err("missing argument {argument}".to_string()); - }; - - let sexp_serialized = - Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(use_sexp_text.clone()))) - .map_err(|e| format!("{e:?}"))?; - - let mut prog_stream = Stream::new(Some(sexp_serialized)); - - sexp_from_stream( - allocator, - &mut prog_stream, - Box::new(SimpleCreateCLVMObject {}), - ) - .map(|x| ParsedInputPathOrCode { - path, - content: use_sexp_text, - parsed: x.1, - }) - .map_err(|e| format!("{e:?}")) - } - _ => { - let (path, use_sexp_text) = if let Some(r) = - get_string_and_filename_with_default(parsed_args, argument, default_sexp) - { - r - } else { - return Err(format!("missing argument {argument}")); - }; - - read_ir(&use_sexp_text) - .map_err(|e| format!("{e:?}")) - .and_then(|v| { - Ok(ParsedInputPathOrCode { - path, - content: use_sexp_text, - parsed: assemble_from_ir(allocator, Rc::new(v)) - .map_err(|e| format!("{e:?}"))?, - }) - }) - } - } -} - pub fn cldb(args: &[String]) { let tool_name = "cldb".to_string(); let props = TArgumentParserProps { @@ -672,17 +596,11 @@ pub fn cldb(args: &[String]) { println!("{}", yamlette_string(output)); }; - let parsed_program_result = - match parse_tool_input_sexp(&mut allocator, "path_or_code", &parsed_args, None, None) { - Ok(r) => r, - Err(e) => { - errorize(&mut output, None, &e.to_string()); - return; - } - }; - - let parsed_args_result = - match parse_tool_input_sexp(&mut allocator, "env", &parsed_args, Some("80"), Some("()")) { + let parsed = + match RunAndCompileInputData::new( + &mut allocator, + &parsed_args + ) { Ok(r) => r, Err(e) => { errorize(&mut output, None, &e.to_string()); @@ -708,7 +626,7 @@ pub fn cldb(args: &[String]) { .map(|x| matches!(x, ArgumentValue::ArgBool(true))) .unwrap_or_else(|| false); let runner = Rc::new(DefaultProgramRunner::new()); - let use_filename = parsed_program_result + let use_filename = parsed.program .path .clone() .unwrap_or_else(|| "*command*".to_string()); @@ -723,7 +641,7 @@ pub fn cldb(args: &[String]) { &mut allocator, &use_symbol_table, prog_srcloc.clone(), - &parsed_program_result.content, + &parsed.program.content, ) .map_err(|_| CompileErr(prog_srcloc, "Failed to parse hex".to_string())), _ => { @@ -733,7 +651,7 @@ pub fn cldb(args: &[String]) { &mut allocator, runner.clone(), opts.clone(), - &parsed_program_result.content, + &parsed.program.content, &mut use_symbol_table, ); unopt_res.and_then(|x| { @@ -762,7 +680,7 @@ pub fn cldb(args: &[String]) { &mut allocator, &HashMap::new(), args_srcloc, - &parsed_args_result.content, + &parsed.args.content, ) { Ok(r) => { args = r; @@ -776,7 +694,7 @@ pub fn cldb(args: &[String]) { } } } - _ => match parse_sexp(Srcloc::start("*arg*"), parsed_args_result.content.bytes()) { + _ => match parse_sexp(Srcloc::start("*arg*"), parsed.args.content.bytes()) { Ok(r) => { if !r.is_empty() { args = r[0].clone(); @@ -801,14 +719,14 @@ pub fn cldb(args: &[String]) { prim_map.insert(p.0.clone(), Rc::new(p.1.clone())); } let program_lines: Rc> = Rc::new( - parsed_program_result + parsed.program .content .lines() .map(|x| x.to_string()) .collect(), ); let cldbenv = CldbRunEnv::new( - parsed_program_result.path.clone(), + parsed.program.path.clone(), program_lines.clone(), Box::new(CldbNoOverride::new_symbols(use_symbol_table.clone())), ); @@ -817,7 +735,7 @@ pub fn cldb(args: &[String]) { let result = cldb_hierarchy( runner, Rc::new(prim_map), - parsed_program_result.path.clone(), + parsed.program.path.clone(), program_lines, Rc::new(use_symbol_table), program, @@ -1273,26 +1191,21 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let dpr = special_runner.clone(); let run_program = special_runner; - let assembled_sexp = - match parse_tool_input_sexp(&mut allocator, "path_or_code", &parsed_args, None, None) { - Ok(s) => s, + let parsed = + match RunAndCompileInputData::new( + &mut allocator, + &parsed_args + ) { + Ok(r) => r, Err(e) => { stdout.write_str(&format!("FAIL: {e}\n")); return; } }; - let env = match parse_tool_input_sexp(&mut allocator, "env", &parsed_args, None, None) { - Ok(s) => s, - Err(e) => { - stdout.write_str(&format!("FAIL: {e}\n")); - return; - } - }; - let time_assemble = SystemTime::now(); - let input_sexp = allocator.new_pair(assembled_sexp.parsed, env.parsed).ok(); + let input_sexp = allocator.new_pair(parsed.program.parsed, parsed.args.parsed).ok(); // Symbol table related checks: should one be loaded, should one be saved. // This code is confusingly woven due to 'run' and 'brun' serving many roles. @@ -1330,9 +1243,8 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .unwrap_or(false); // Dialect is now not overall optional. - let dialect = input_sexp.map(|i| detect_modern(&mut allocator, i)); let mut stderr_output = |s: String| { - if dialect.as_ref().and_then(|d| d.stepping).is_some() { + if parsed.dialect.stepping.is_some() { eprintln!("{s}"); } else { stdout.write_str(&s); @@ -1368,7 +1280,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(stepping) = dialect.as_ref().and_then(|d| d.stepping) { + if let Some(stepping) = parsed.dialect.stepping { let do_optimize = parsed_args .get("optimize") .map(|x| matches!(x, ArgumentValue::ArgBool(true))) @@ -1376,7 +1288,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_default()) + .set_dialect(parsed.dialect) .set_optimize(do_optimize || stepping > 22) .set_search_paths(&search_paths) .set_frontend_opt(stepping == 22) diff --git a/src/classic/clvm_tools/comp_input.rs b/src/classic/clvm_tools/comp_input.rs new file mode 100644 index 000000000..280b8765e --- /dev/null +++ b/src/classic/clvm_tools/comp_input.rs @@ -0,0 +1,126 @@ +use std::collections::HashMap; +use std::rc::Rc; + +use clvmr::{Allocator, NodePtr}; + +use crate::classic::platform::argparse::ArgumentValue; +use crate::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType}; +use crate::classic::clvm::serialize::{SimpleCreateCLVMObject, sexp_from_stream}; + +use crate::classic::clvm_tools::binutils::assemble_from_ir; +use crate::classic::clvm_tools::ir::reader::read_ir; + +use crate::compiler::dialect::{AcceptedDialect, detect_modern}; + +fn get_string_and_filename_with_default( + parsed_args: &HashMap, + argument: &str, + default: Option<&str>, +) -> Option<(Option, String)> { + if let Some(ArgumentValue::ArgString(path, content)) = parsed_args.get(argument) { + Some((path.clone(), content.to_string())) + } else { + default.map(|p| (None, p.to_string())) + } +} + +pub struct ParsedInputPathOrCode { + pub path: Option, + pub content: String, + pub parsed: NodePtr, +} + +pub fn parse_tool_input_sexp( + allocator: &mut Allocator, + argument: &str, + parsed_args: &HashMap, + default_hex: Option<&str>, + default_sexp: Option<&str>, +) -> Result { + match parsed_args.get("hex") { + Some(_) => { + let (path, use_sexp_text) = if let Some(r) = + get_string_and_filename_with_default(parsed_args, argument, default_hex) + { + r + } else { + return Err("missing argument {argument}".to_string()); + }; + + let sexp_serialized = + Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(use_sexp_text.clone()))) + .map_err(|e| format!("{e:?}"))?; + + let mut prog_stream = Stream::new(Some(sexp_serialized)); + + sexp_from_stream( + allocator, + &mut prog_stream, + Box::new(SimpleCreateCLVMObject {}), + ) + .map(|x| ParsedInputPathOrCode { + path, + content: use_sexp_text, + parsed: x.1, + }) + .map_err(|e| format!("{e:?}")) + } + _ => { + let (path, use_sexp_text) = if let Some(r) = + get_string_and_filename_with_default(parsed_args, argument, default_sexp) + { + r + } else { + return Err(format!("missing argument {argument}")); + }; + + read_ir(&use_sexp_text) + .map_err(|e| format!("{e:?}")) + .and_then(|v| { + Ok(ParsedInputPathOrCode { + path, + content: use_sexp_text, + parsed: assemble_from_ir(allocator, Rc::new(v)) + .map_err(|e| format!("{e:?}"))? + }) + }) + } + } +} + +pub struct RunAndCompileInputData { + pub program: ParsedInputPathOrCode, + pub args: ParsedInputPathOrCode, + pub dialect: AcceptedDialect, +} + +impl RunAndCompileInputData { + pub fn new( + allocator: &mut Allocator, + parsed_args: &HashMap + ) -> Result { + let program = parse_tool_input_sexp( + allocator, + "path_or_code", + parsed_args, + None, + None + )?; + let args = parse_tool_input_sexp( + allocator, + "env", + parsed_args, + Some("80"), + Some("()"), + )?; + let dialect = detect_modern( + allocator, + program.parsed + ); + Ok(RunAndCompileInputData { + program, + args, + dialect, + }) + } +} diff --git a/src/classic/clvm_tools/mod.rs b/src/classic/clvm_tools/mod.rs index a5bd88464..9bbdfbe58 100644 --- a/src/classic/clvm_tools/mod.rs +++ b/src/classic/clvm_tools/mod.rs @@ -1,6 +1,7 @@ pub mod binutils; pub mod clvmc; pub mod cmds; +pub mod comp_input; pub mod curry; pub mod debug; pub mod ir; From f992752410b75eb84e0497b2084619e4c15d06cd Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 5 Jul 2024 11:35:17 -0700 Subject: [PATCH 3/8] fmt + clippy --- src/classic/clvm_tools/cmds.rs | 46 +++++++++++++--------------- src/classic/clvm_tools/comp_input.rs | 31 +++++-------------- 2 files changed, 29 insertions(+), 48 deletions(-) diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index d2dd0c816..536085a46 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -596,17 +596,13 @@ pub fn cldb(args: &[String]) { println!("{}", yamlette_string(output)); }; - let parsed = - match RunAndCompileInputData::new( - &mut allocator, - &parsed_args - ) { - Ok(r) => r, - Err(e) => { - errorize(&mut output, None, &e.to_string()); - return; - } - }; + let parsed = match RunAndCompileInputData::new(&mut allocator, &parsed_args) { + Ok(r) => r, + Err(e) => { + errorize(&mut output, None, &e.to_string()); + return; + } + }; let symbol_table = parsed_args .get("symbol_table") @@ -626,7 +622,8 @@ pub fn cldb(args: &[String]) { .map(|x| matches!(x, ArgumentValue::ArgBool(true))) .unwrap_or_else(|| false); let runner = Rc::new(DefaultProgramRunner::new()); - let use_filename = parsed.program + let use_filename = parsed + .program .path .clone() .unwrap_or_else(|| "*command*".to_string()); @@ -719,7 +716,8 @@ pub fn cldb(args: &[String]) { prim_map.insert(p.0.clone(), Rc::new(p.1.clone())); } let program_lines: Rc> = Rc::new( - parsed.program + parsed + .program .content .lines() .map(|x| x.to_string()) @@ -1191,21 +1189,19 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let dpr = special_runner.clone(); let run_program = special_runner; - let parsed = - match RunAndCompileInputData::new( - &mut allocator, - &parsed_args - ) { - Ok(r) => r, - Err(e) => { - stdout.write_str(&format!("FAIL: {e}\n")); - return; - } - }; + let parsed = match RunAndCompileInputData::new(&mut allocator, &parsed_args) { + Ok(r) => r, + Err(e) => { + stdout.write_str(&format!("FAIL: {e}\n")); + return; + } + }; let time_assemble = SystemTime::now(); - let input_sexp = allocator.new_pair(parsed.program.parsed, parsed.args.parsed).ok(); + let input_sexp = allocator + .new_pair(parsed.program.parsed, parsed.args.parsed) + .ok(); // Symbol table related checks: should one be loaded, should one be saved. // This code is confusingly woven due to 'run' and 'brun' serving many roles. diff --git a/src/classic/clvm_tools/comp_input.rs b/src/classic/clvm_tools/comp_input.rs index 280b8765e..b2d4d138a 100644 --- a/src/classic/clvm_tools/comp_input.rs +++ b/src/classic/clvm_tools/comp_input.rs @@ -3,14 +3,14 @@ use std::rc::Rc; use clvmr::{Allocator, NodePtr}; -use crate::classic::platform::argparse::ArgumentValue; use crate::classic::clvm::__type_compatibility__::{Bytes, Stream, UnvalidatedBytesFromType}; -use crate::classic::clvm::serialize::{SimpleCreateCLVMObject, sexp_from_stream}; +use crate::classic::clvm::serialize::{sexp_from_stream, SimpleCreateCLVMObject}; +use crate::classic::platform::argparse::ArgumentValue; use crate::classic::clvm_tools::binutils::assemble_from_ir; use crate::classic::clvm_tools::ir::reader::read_ir; -use crate::compiler::dialect::{AcceptedDialect, detect_modern}; +use crate::compiler::dialect::{detect_modern, AcceptedDialect}; fn get_string_and_filename_with_default( parsed_args: &HashMap, @@ -81,7 +81,7 @@ pub fn parse_tool_input_sexp( path, content: use_sexp_text, parsed: assemble_from_ir(allocator, Rc::new(v)) - .map_err(|e| format!("{e:?}"))? + .map_err(|e| format!("{e:?}"))?, }) }) } @@ -97,26 +97,11 @@ pub struct RunAndCompileInputData { impl RunAndCompileInputData { pub fn new( allocator: &mut Allocator, - parsed_args: &HashMap + parsed_args: &HashMap, ) -> Result { - let program = parse_tool_input_sexp( - allocator, - "path_or_code", - parsed_args, - None, - None - )?; - let args = parse_tool_input_sexp( - allocator, - "env", - parsed_args, - Some("80"), - Some("()"), - )?; - let dialect = detect_modern( - allocator, - program.parsed - ); + let program = parse_tool_input_sexp(allocator, "path_or_code", parsed_args, None, None)?; + let args = parse_tool_input_sexp(allocator, "env", parsed_args, Some("80"), Some("()"))?; + let dialect = detect_modern(allocator, program.parsed); Ok(RunAndCompileInputData { program, args, From d40b2da54e9366fb908ad40fca14dd6d63ecdaa0 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 5 Jul 2024 12:28:53 -0700 Subject: [PATCH 4/8] Make modern compilation equal between run and cldb and factor this code out from run into the new comp_input --- src/classic/clvm_tools/cmds.rs | 255 +++++++++------------------ src/classic/clvm_tools/comp_input.rs | 107 +++++++++++ 2 files changed, 186 insertions(+), 176 deletions(-) diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 536085a46..a9b314587 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -30,7 +30,7 @@ use crate::classic::clvm::sexp::{enlist, proper_list, sexp_as_bin}; use crate::classic::clvm::OPERATORS_LATEST_VERSION; use crate::classic::clvm_tools::binutils::{assemble_from_ir, disassemble, disassemble_with_kw}; use crate::classic::clvm_tools::clvmc::write_sym_output; -use crate::classic::clvm_tools::comp_input::RunAndCompileInputData; +use crate::classic::clvm_tools::comp_input::{get_disassembly_ver, RunAndCompileInputData}; 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,11 +53,9 @@ 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, DefaultCompilerOpts}; +use crate::compiler::compiler::DefaultCompilerOpts; use crate::compiler::comptypes::{CompileErr, CompilerOpts}; -use crate::compiler::debug::build_symbol_table_mut; use crate::compiler::frontend::frontend; -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; @@ -497,13 +495,15 @@ pub fn cldb_hierarchy( } pub fn cldb(args: &[String]) { + let mut allocator = Allocator::new(); + let mut output = Vec::new(); + let tool_name = "cldb".to_string(); let props = TArgumentParserProps { description: "Execute a clvm script.".to_string(), prog: format!("clvm_tools {tool_name}"), }; - let mut search_paths = Vec::new(); let mut parser = ArgumentParser::new(Some(props)); parser.add_argument( vec!["-i".to_string(), "--include".to_string()], @@ -561,27 +561,6 @@ pub fn cldb(args: &[String]) { let prog_srcloc = Srcloc::start("*program*"); let args_srcloc = Srcloc::start("*args*"); - let mut args = Rc::new(sexp::SExp::atom_from_string(args_srcloc.clone(), "")); - - let parsed_args: HashMap = match parser.parse_args(&arg_vec) { - Err(e) => { - println!("FAIL: {e}"); - return; - } - Ok(pa) => pa, - }; - - if let Some(ArgumentValue::ArgArray(v)) = parsed_args.get("include") { - for p in v { - if let ArgumentValue::ArgString(_, s) = p { - search_paths.push(s.to_string()); - } - } - } - - let mut allocator = Allocator::new(); - let mut output = Vec::new(); - let errorize = |output: &mut Vec>, location: Option, c: &str| { let mut parse_error = BTreeMap::new(); @@ -596,12 +575,12 @@ pub fn cldb(args: &[String]) { println!("{}", yamlette_string(output)); }; - let parsed = match RunAndCompileInputData::new(&mut allocator, &parsed_args) { - Ok(r) => r, + let parsed_args: HashMap = match parser.parse_args(&arg_vec) { Err(e) => { - errorize(&mut output, None, &e.to_string()); + println!("FAIL: {e}"); return; } + Ok(pa) => pa, }; let symbol_table = parsed_args @@ -615,21 +594,20 @@ pub fn cldb(args: &[String]) { _ => None, }); + let parsed = match RunAndCompileInputData::new( + &mut allocator, + &parsed_args + ) { + Ok(r) => r, + Err(e) => { + println!("FAIL: {e}"); + return; + } + }; + let only_print = parsed_args.get("only_print").map(|_| true).unwrap_or(false); - let do_optimize = parsed_args - .get("optimize") - .map(|x| matches!(x, ArgumentValue::ArgBool(true))) - .unwrap_or_else(|| false); let runner = Rc::new(DefaultProgramRunner::new()); - let use_filename = parsed - .program - .path - .clone() - .unwrap_or_else(|| "*command*".to_string()); - let opts = Rc::new(DefaultCompilerOpts::new(&use_filename)) - .set_optimize(do_optimize) - .set_search_paths(&search_paths); let mut use_symbol_table = symbol_table.unwrap_or_default(); @@ -642,24 +620,7 @@ pub fn cldb(args: &[String]) { ) .map_err(|_| CompileErr(prog_srcloc, "Failed to parse hex".to_string())), _ => { - // don't clobber a symbol table brought in via -y unless we're - // compiling here. - let unopt_res = compile_file( - &mut allocator, - runner.clone(), - opts.clone(), - &parsed.program.content, - &mut use_symbol_table, - ); - unopt_res.and_then(|x| { - maybe_finalize_program_via_classic_optimizer( - &mut allocator, - runner.clone(), - opts, - false, - &x, - ) - }) + parsed.compile_modern(&mut allocator, &mut use_symbol_table) } }; @@ -671,45 +632,48 @@ pub fn cldb(args: &[String]) { } }; - match parsed_args.get("hex") { - Some(ArgumentValue::ArgBool(true)) => { - match hex_to_modern_sexp( - &mut allocator, - &HashMap::new(), - args_srcloc, - &parsed.args.content, - ) { + let env_loc = Srcloc::start("*args*"); + let env = + match parsed_args.get("hex") { + Some(ArgumentValue::ArgBool(true)) => { + match hex_to_modern_sexp( + &mut allocator, + &HashMap::new(), + args_srcloc, + &parsed.args.content, + ) { + Ok(r) => r, + Err(p) => { + let mut parse_error = BTreeMap::new(); + parse_error.insert("Error".to_string(), YamlElement::String(p.to_string())); + output.push(parse_error.clone()); + println!("{}", yamlette_string(&output)); + return; + } + } + } + + _ => match parse_sexp(env_loc.clone(), parsed.args.content.bytes()) { Ok(r) => { - args = r; + if !r.is_empty() { + r[0].clone() + } else { + Rc::new(sexp::SExp::Nil(env_loc)) + } } - Err(p) => { + Err(c) => { let mut parse_error = BTreeMap::new(); - parse_error.insert("Error".to_string(), YamlElement::String(p.to_string())); + parse_error.insert( + "Error-Location".to_string(), + YamlElement::String(c.0.to_string()), + ); + parse_error.insert("Error".to_string(), YamlElement::String(c.1)); output.push(parse_error.clone()); println!("{}", yamlette_string(&output)); return; } } - } - _ => match parse_sexp(Srcloc::start("*arg*"), parsed.args.content.bytes()) { - Ok(r) => { - if !r.is_empty() { - args = r[0].clone(); - } - } - Err(c) => { - let mut parse_error = BTreeMap::new(); - parse_error.insert( - "Error-Location".to_string(), - YamlElement::String(c.0.to_string()), - ); - parse_error.insert("Error".to_string(), YamlElement::String(c.1)); - output.push(parse_error.clone()); - println!("{}", yamlette_string(&output)); - return; - } - }, - }; + }; let mut prim_map = HashMap::new(); for p in prims::prims().iter() { @@ -737,7 +701,7 @@ pub fn cldb(args: &[String]) { program_lines, Rc::new(use_symbol_table), program, - args, + env, ); // Print the tree @@ -746,7 +710,7 @@ pub fn cldb(args: &[String]) { return; } - let step = start_step(program, args); + let step = start_step(program, env); let mut cldbrun = CldbRun::new(runner, Rc::new(prim_map), Box::new(cldbenv), step); let print_tree = |output: &mut Vec<_>, result: &BTreeMap| { let mut cvt_subtree = BTreeMap::new(); @@ -916,15 +880,9 @@ fn perform_preprocessing( Ok(()) } -fn get_disassembly_ver(p: &HashMap) -> Option { - if let Some(ArgumentValue::ArgInt(x)) = p.get("operators_version") { - return Some(*x as usize); - } - - None -} - pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, default_stage: u32) { + let mut allocator = Allocator::new(); + let props = TArgumentParserProps { description: "Execute a clvm script.".to_string(), prog: format!("clvm_tools {tool_name}"), @@ -1107,6 +1065,14 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul return; } + let parsed = match RunAndCompileInputData::new(&mut allocator, &parsed_args) { + Ok(r) => r, + Err(e) => { + stdout.write_str(&format!("FAIL: {e}\n")); + return; + } + }; + let empty_map = HashMap::new(); let keywords = match parsed_args.get("no_keywords") { Some(ArgumentValue::ArgBool(_b)) => &empty_map, @@ -1136,22 +1102,6 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul .cloned() .unwrap_or_else(|| "*command*".to_string()); - let search_paths = if let Some(ArgumentValue::ArgArray(v)) = parsed_args.get("include") { - v.iter() - .filter_map(|p| { - if let ArgumentValue::ArgString(_, s) = p { - Some(s.to_string()) - } else { - None - } - }) - .collect() - } else { - Vec::new() - }; - - let mut allocator = Allocator::new(); - let time_start = SystemTime::now(); let time_read_hex = SystemTime::now(); @@ -1163,7 +1113,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul parsed_args.get("path_or_code"), ) { if let Some(filename) = &file { - let opts = DefaultCompilerOpts::new(filename).set_search_paths(&search_paths); + let opts = DefaultCompilerOpts::new(filename).set_search_paths(&parsed.search_paths); match gather_dependencies(opts, filename, file_content) { Err(e) => { @@ -1183,20 +1133,12 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul } let special_runner = - run_program_for_search_paths(&reported_input_file, &search_paths, extra_symbol_info); + run_program_for_search_paths(&reported_input_file, &parsed.search_paths, extra_symbol_info); // Ensure we know the user's wishes about the disassembly version here. special_runner.set_operators_version(get_disassembly_ver(&parsed_args)); let dpr = special_runner.clone(); let run_program = special_runner; - let parsed = match RunAndCompileInputData::new(&mut allocator, &parsed_args) { - Ok(r) => r, - Err(e) => { - stdout.write_str(&format!("FAIL: {e}\n")); - return; - } - }; - let time_assemble = SystemTime::now(); let input_sexp = allocator @@ -1249,7 +1191,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul if do_check_unused { let opts = - Rc::new(DefaultCompilerOpts::new(&reported_input_file)).set_search_paths(&search_paths); + Rc::new(DefaultCompilerOpts::new(&reported_input_file)).set_search_paths(&parsed.search_paths); match check_unused(opts, &input_program) { Ok((success, output)) => { stderr_output(output); @@ -1264,70 +1206,31 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul } } - let symbol_table_output = parsed_args - .get("symbol_output_file") - .and_then(|s| { - if let ArgumentValue::ArgString(_, v) = s { - Some(v.clone()) - } else { - None - } - }) - .unwrap_or_else(|| "main.sym".to_string()); - // In testing: short circuit for modern compilation. - if let Some(stepping) = parsed.dialect.stepping { - let do_optimize = parsed_args - .get("optimize") - .map(|x| matches!(x, ArgumentValue::ArgBool(true))) - .unwrap_or_else(|| false); - 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(parsed.dialect) - .set_optimize(do_optimize || stepping > 22) - .set_search_paths(&search_paths) - .set_frontend_opt(stepping == 22) - .set_disassembly_ver(get_disassembly_ver(&parsed_args)); - let mut symbol_table = HashMap::new(); - + if parsed.dialect.stepping.is_some() { // Short circuit preprocessing display. if parsed_args.contains_key("preprocess") { - if let Err(e) = perform_preprocessing(stdout, opts, &use_filename, &input_program) { + if let Err(e) = perform_preprocessing(stdout, parsed.opts.clone(), &parsed.use_filename(), &input_program) { stdout.write_str(&format!("{}: {}", e.0, e.1)); } return; } - let unopt_res = compile_file( - &mut allocator, - runner.clone(), - opts.clone(), - &input_program, - &mut symbol_table, - ); - let res = unopt_res.and_then(|x| { - maybe_finalize_program_via_classic_optimizer( - &mut allocator, - runner, - opts, - do_optimize, - &x, - ) - }); + let mut symbol_table = HashMap::new(); + match parsed.compile_modern(&mut allocator, &mut symbol_table).and_then(|r| { + write_sym_output(&symbol_table, &parsed.symbol_table_output).map_err(|e| { + CompileErr(Srcloc::start(&parsed.use_filename()), format!("writing symbols: {e:?}")) + })?; - match res { + Ok(r) + }) { Ok(r) => { stdout.write_str(&r.to_string()); - - build_symbol_table_mut(&mut symbol_table, &r); - write_sym_output(&symbol_table, &symbol_table_output).expect("writing symbols"); } Err(c) => { stdout.write_str(&format!("{}: {}", c.0, c.1)); } } - return; } @@ -1547,7 +1450,7 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let compile_sym_out = dpr.get_compiles(); if !compile_sym_out.is_empty() { - write_sym_output(&compile_sym_out, &symbol_table_output).ok(); + write_sym_output(&compile_sym_out, &parsed.symbol_table_output).ok(); } stdout.write_str(&format!("{output}\n")); diff --git a/src/classic/clvm_tools/comp_input.rs b/src/classic/clvm_tools/comp_input.rs index b2d4d138a..6a171e878 100644 --- a/src/classic/clvm_tools/comp_input.rs +++ b/src/classic/clvm_tools/comp_input.rs @@ -9,8 +9,22 @@ use crate::classic::platform::argparse::ArgumentValue; use crate::classic::clvm_tools::binutils::assemble_from_ir; use crate::classic::clvm_tools::ir::reader::read_ir; +use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; +use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; +use crate::compiler::comptypes::{CompilerOpts, CompileErr}; +use crate::compiler::debug::build_symbol_table_mut; use crate::compiler::dialect::{detect_modern, AcceptedDialect}; +use crate::compiler::optimize::maybe_finalize_program_via_classic_optimizer; +use crate::compiler::sexp; + +pub fn get_disassembly_ver(p: &HashMap) -> Option { + if let Some(ArgumentValue::ArgInt(x)) = p.get("operators_version") { + return Some(*x as usize); + } + + None +} fn get_string_and_filename_with_default( parsed_args: &HashMap, @@ -30,6 +44,15 @@ pub struct ParsedInputPathOrCode { pub parsed: NodePtr, } +impl ParsedInputPathOrCode { + pub fn use_filename(&self) -> String { + self + .path + .clone() + .unwrap_or_else(|| "*command*".to_string()) + } +} + pub fn parse_tool_input_sexp( allocator: &mut Allocator, argument: &str, @@ -92,6 +115,10 @@ pub struct RunAndCompileInputData { pub program: ParsedInputPathOrCode, pub args: ParsedInputPathOrCode, pub dialect: AcceptedDialect, + pub opts: Rc, + pub do_optimize: bool, + pub search_paths: Vec, + pub symbol_table_output: String, } impl RunAndCompileInputData { @@ -102,10 +129,90 @@ impl RunAndCompileInputData { let program = parse_tool_input_sexp(allocator, "path_or_code", parsed_args, None, None)?; let args = parse_tool_input_sexp(allocator, "env", parsed_args, Some("80"), Some("()"))?; let dialect = detect_modern(allocator, program.parsed); + + let do_optimize = parsed_args + .get("optimize") + .map(|x| matches!(x, ArgumentValue::ArgBool(true))) + .unwrap_or_else(|| false); + + let search_paths = if let Some(ArgumentValue::ArgArray(v)) = parsed_args.get("include") { + v.iter() + .filter_map(|p| { + if let ArgumentValue::ArgString(_, s) = p { + Some(s.to_string()) + } else { + None + } + }) + .collect() + } else { + Vec::new() + }; + + let mut opts: Rc = Rc::new(DefaultCompilerOpts::new(&program.use_filename())) + .set_dialect(dialect.clone()) + .set_search_paths(&search_paths) + .set_optimize(do_optimize) + .set_disassembly_ver(get_disassembly_ver(&parsed_args)); + + if let Some(stepping) = dialect.stepping { + opts = opts + .set_optimize(do_optimize || stepping > 22) + .set_frontend_opt(stepping == 22); + } + + let symbol_table_output = parsed_args + .get("symbol_output_file") + .and_then(|s| { + if let ArgumentValue::ArgString(_, v) = s { + Some(v.clone()) + } else { + None + } + }) + .unwrap_or_else(|| "main.sym".to_string()); + Ok(RunAndCompileInputData { program, args, dialect, + do_optimize, + search_paths, + opts, + symbol_table_output, }) } + + pub fn use_filename(&self) -> String { + self.program.path.clone().unwrap_or_else(|| "*command*".to_string()) + } + + pub fn compile_modern( + &self, + allocator: &mut Allocator, + symbol_table: &mut HashMap, + ) -> Result, CompileErr> { + let runner = Rc::new(DefaultProgramRunner::new()); + + let unopt_res = compile_file( + allocator, + runner.clone(), + self.opts.clone(), + &self.program.content, + symbol_table, + ); + let res = unopt_res.and_then(|x| { + maybe_finalize_program_via_classic_optimizer( + allocator, + runner, + self.opts.clone(), + self.do_optimize, + &x, + ) + })?; + + build_symbol_table_mut(symbol_table, &res); + + Ok(res) + } } From 3e16cb2b46b9070a314a99e11872ea1f2cb2cc6b Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 5 Jul 2024 12:37:28 -0700 Subject: [PATCH 5/8] Tighten further by eliminating some duplicated computations --- src/classic/clvm_tools/cmds.rs | 136 +++++++++++++-------------- src/classic/clvm_tools/comp_input.rs | 23 ++--- 2 files changed, 76 insertions(+), 83 deletions(-) diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index a9b314587..374c2f1f6 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -594,10 +594,7 @@ pub fn cldb(args: &[String]) { _ => None, }); - let parsed = match RunAndCompileInputData::new( - &mut allocator, - &parsed_args - ) { + let parsed = match RunAndCompileInputData::new(&mut allocator, &parsed_args) { Ok(r) => r, Err(e) => { println!("FAIL: {e}"); @@ -619,9 +616,7 @@ pub fn cldb(args: &[String]) { &parsed.program.content, ) .map_err(|_| CompileErr(prog_srcloc, "Failed to parse hex".to_string())), - _ => { - parsed.compile_modern(&mut allocator, &mut use_symbol_table) - } + _ => parsed.compile_modern(&mut allocator, &mut use_symbol_table), }; let program = match res { @@ -633,47 +628,46 @@ pub fn cldb(args: &[String]) { }; let env_loc = Srcloc::start("*args*"); - let env = - match parsed_args.get("hex") { - Some(ArgumentValue::ArgBool(true)) => { - match hex_to_modern_sexp( - &mut allocator, - &HashMap::new(), - args_srcloc, - &parsed.args.content, - ) { - Ok(r) => r, - Err(p) => { - let mut parse_error = BTreeMap::new(); - parse_error.insert("Error".to_string(), YamlElement::String(p.to_string())); - output.push(parse_error.clone()); - println!("{}", yamlette_string(&output)); - return; - } - } - } - - _ => match parse_sexp(env_loc.clone(), parsed.args.content.bytes()) { - Ok(r) => { - if !r.is_empty() { - r[0].clone() - } else { - Rc::new(sexp::SExp::Nil(env_loc)) - } - } - Err(c) => { + let env = match parsed_args.get("hex") { + Some(ArgumentValue::ArgBool(true)) => { + match hex_to_modern_sexp( + &mut allocator, + &HashMap::new(), + args_srcloc, + &parsed.args.content, + ) { + Ok(r) => r, + Err(p) => { let mut parse_error = BTreeMap::new(); - parse_error.insert( - "Error-Location".to_string(), - YamlElement::String(c.0.to_string()), - ); - parse_error.insert("Error".to_string(), YamlElement::String(c.1)); + parse_error.insert("Error".to_string(), YamlElement::String(p.to_string())); output.push(parse_error.clone()); println!("{}", yamlette_string(&output)); return; } } - }; + } + + _ => match parse_sexp(env_loc.clone(), parsed.args.content.bytes()) { + Ok(r) => { + if !r.is_empty() { + r[0].clone() + } else { + Rc::new(sexp::SExp::Nil(env_loc)) + } + } + Err(c) => { + let mut parse_error = BTreeMap::new(); + parse_error.insert( + "Error-Location".to_string(), + YamlElement::String(c.0.to_string()), + ); + parse_error.insert("Error".to_string(), YamlElement::String(c.1)); + output.push(parse_error.clone()); + println!("{}", yamlette_string(&output)); + return; + } + }, + }; let mut prim_map = HashMap::new(); for p in prims::prims().iter() { @@ -1085,23 +1079,6 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul // more info). let extra_symbol_info = parsed_args.get("extra_syms").map(|_| true).unwrap_or(false); - // Get name of included file so we can use it to initialize the compiler's - // runner, which contains operators used at compile time in clvm to update - // symbols. This is the only means we have of communicating with the - // compilation process from this level. - let mut input_file = None; - let mut input_program = "()".to_string(); - - if let Some(ArgumentValue::ArgString(file, path_or_code)) = parsed_args.get("path_or_code") { - input_file.clone_from(file); - input_program = path_or_code.to_string(); - } - - let reported_input_file = input_file - .as_ref() - .cloned() - .unwrap_or_else(|| "*command*".to_string()); - let time_start = SystemTime::now(); let time_read_hex = SystemTime::now(); @@ -1132,8 +1109,11 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul return; } - let special_runner = - run_program_for_search_paths(&reported_input_file, &parsed.search_paths, extra_symbol_info); + let special_runner = run_program_for_search_paths( + &parsed.use_filename(), + &parsed.search_paths, + extra_symbol_info, + ); // Ensure we know the user's wishes about the disassembly version here. special_runner.set_operators_version(get_disassembly_ver(&parsed_args)); let dpr = special_runner.clone(); @@ -1190,9 +1170,9 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul }; if do_check_unused { - let opts = - Rc::new(DefaultCompilerOpts::new(&reported_input_file)).set_search_paths(&parsed.search_paths); - match check_unused(opts, &input_program) { + let opts = Rc::new(DefaultCompilerOpts::new(&parsed.use_filename())) + .set_search_paths(&parsed.search_paths); + match check_unused(opts, &parsed.program.content) { Ok((success, output)) => { stderr_output(output); if !success { @@ -1210,20 +1190,32 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul if parsed.dialect.stepping.is_some() { // Short circuit preprocessing display. if parsed_args.contains_key("preprocess") { - if let Err(e) = perform_preprocessing(stdout, parsed.opts.clone(), &parsed.use_filename(), &input_program) { + if let Err(e) = perform_preprocessing( + stdout, + parsed.opts.clone(), + &parsed.use_filename(), + &parsed.program.content, + ) { stdout.write_str(&format!("{}: {}", e.0, e.1)); } return; } let mut symbol_table = HashMap::new(); - match parsed.compile_modern(&mut allocator, &mut symbol_table).and_then(|r| { - write_sym_output(&symbol_table, &parsed.symbol_table_output).map_err(|e| { - CompileErr(Srcloc::start(&parsed.use_filename()), format!("writing symbols: {e:?}")) - })?; - - Ok(r) - }) { + let res = parsed + .compile_modern(&mut allocator, &mut symbol_table) + .and_then(|r| { + write_sym_output(&symbol_table, &parsed.symbol_table_output).map_err(|e| { + CompileErr( + Srcloc::start(&parsed.use_filename()), + format!("writing symbols: {e:?}"), + ) + })?; + + Ok(r) + }); + + match res { Ok(r) => { stdout.write_str(&r.to_string()); } diff --git a/src/classic/clvm_tools/comp_input.rs b/src/classic/clvm_tools/comp_input.rs index 6a171e878..7ce810e03 100644 --- a/src/classic/clvm_tools/comp_input.rs +++ b/src/classic/clvm_tools/comp_input.rs @@ -12,7 +12,7 @@ use crate::classic::clvm_tools::ir::reader::read_ir; use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; -use crate::compiler::comptypes::{CompilerOpts, CompileErr}; +use crate::compiler::comptypes::{CompileErr, CompilerOpts}; use crate::compiler::debug::build_symbol_table_mut; use crate::compiler::dialect::{detect_modern, AcceptedDialect}; use crate::compiler::optimize::maybe_finalize_program_via_classic_optimizer; @@ -46,10 +46,7 @@ pub struct ParsedInputPathOrCode { impl ParsedInputPathOrCode { pub fn use_filename(&self) -> String { - self - .path - .clone() - .unwrap_or_else(|| "*command*".to_string()) + self.path.clone().unwrap_or_else(|| "*command*".to_string()) } } @@ -149,11 +146,12 @@ impl RunAndCompileInputData { Vec::new() }; - let mut opts: Rc = Rc::new(DefaultCompilerOpts::new(&program.use_filename())) - .set_dialect(dialect.clone()) - .set_search_paths(&search_paths) - .set_optimize(do_optimize) - .set_disassembly_ver(get_disassembly_ver(&parsed_args)); + let mut opts: Rc = + Rc::new(DefaultCompilerOpts::new(&program.use_filename())) + .set_dialect(dialect.clone()) + .set_search_paths(&search_paths) + .set_optimize(do_optimize) + .set_disassembly_ver(get_disassembly_ver(parsed_args)); if let Some(stepping) = dialect.stepping { opts = opts @@ -184,7 +182,10 @@ impl RunAndCompileInputData { } pub fn use_filename(&self) -> String { - self.program.path.clone().unwrap_or_else(|| "*command*".to_string()) + self.program + .path + .clone() + .unwrap_or_else(|| "*command*".to_string()) } pub fn compile_modern( From 78d2653d7971b76532e7aa5048505224fb55dfb7 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 5 Jul 2024 13:06:07 -0700 Subject: [PATCH 6/8] Ensure that we take an empty argument as a default when a default value exists --- src/classic/clvm_tools/comp_input.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/classic/clvm_tools/comp_input.rs b/src/classic/clvm_tools/comp_input.rs index 7ce810e03..448a1b52c 100644 --- a/src/classic/clvm_tools/comp_input.rs +++ b/src/classic/clvm_tools/comp_input.rs @@ -59,7 +59,7 @@ pub fn parse_tool_input_sexp( ) -> Result { match parsed_args.get("hex") { Some(_) => { - let (path, use_sexp_text) = if let Some(r) = + let (path, sexp_text) = if let Some(r) = get_string_and_filename_with_default(parsed_args, argument, default_hex) { r @@ -67,6 +67,13 @@ pub fn parse_tool_input_sexp( return Err("missing argument {argument}".to_string()); }; + let use_sexp_text = + if sexp_text.is_empty() { + default_hex.unwrap_or_default() + } else { + &sexp_text + }.to_string(); + let sexp_serialized = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(use_sexp_text.clone()))) .map_err(|e| format!("{e:?}"))?; From 9bb05ff43770ff42c6d6fff99efdddf4e7f99169 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 5 Jul 2024 13:08:26 -0700 Subject: [PATCH 7/8] fmt + clippy --- src/classic/clvm_tools/comp_input.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/classic/clvm_tools/comp_input.rs b/src/classic/clvm_tools/comp_input.rs index 448a1b52c..3216b2535 100644 --- a/src/classic/clvm_tools/comp_input.rs +++ b/src/classic/clvm_tools/comp_input.rs @@ -67,12 +67,12 @@ pub fn parse_tool_input_sexp( return Err("missing argument {argument}".to_string()); }; - let use_sexp_text = - if sexp_text.is_empty() { - default_hex.unwrap_or_default() - } else { - &sexp_text - }.to_string(); + let use_sexp_text = if sexp_text.is_empty() { + default_hex.unwrap_or_default() + } else { + &sexp_text + } + .to_string(); let sexp_serialized = Bytes::new_validated(Some(UnvalidatedBytesFromType::Hex(use_sexp_text.clone()))) From 58138187802ea646626766f7bdac0ff5bdfdae73 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 22 Jul 2024 09:40:17 -0700 Subject: [PATCH 8/8] Remove test code --- src/tests/compiler/cldb.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/compiler/cldb.rs b/src/tests/compiler/cldb.rs index c22074a22..0c6e7e2ff 100644 --- a/src/tests/compiler/cldb.rs +++ b/src/tests/compiler/cldb.rs @@ -334,7 +334,6 @@ impl ExpectFailure { impl StepOfCldbViewer for ExpectFailure { fn show(&mut self, _step: &RunStep, output: Option>) -> bool { - eprintln!("{:?}", output); if let Some(o) = output { if let Some(_) = o.get("Failure") { let did_throw = o.get("Operator") == Some(&"8".to_string());