diff --git a/add_integers.uplc b/add_integers.uplc index fa621147..0ca9825e 100644 --- a/add_integers.uplc +++ b/add_integers.uplc @@ -1,5 +1,4 @@ (program 1.0.0 - [(force (force (builtin fstPair))) (con (pair integer bytestring) (22, #1122aabb))] -) - + (lam y (lam x [ [ (builtin addInteger) x ] y ])) +) \ No newline at end of file diff --git a/crates/cli/src/args.rs b/crates/cli/src/args.rs index fcbe306c..032c36b1 100644 --- a/crates/cli/src/args.rs +++ b/crates/cli/src/args.rs @@ -39,9 +39,11 @@ pub enum UplcCommand { }, /// Evaluate an Untyped Plutus Core program Eval { - input: PathBuf, + script: PathBuf, #[clap(short, long)] flat: bool, + /// Arguments to pass to the uplc program + args: Vec, }, } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 4bc26704..322fca9a 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -82,21 +82,28 @@ fn main() -> anyhow::Result<()> { fs::write(&out_name, pretty)?; } } - UplcCommand::Eval { input, flat } => { - let program = if flat { - let bytes = std::fs::read(&input)?; + + UplcCommand::Eval { script, flat, args } => { + let mut program = if flat { + let bytes = std::fs::read(&script)?; let prog = Program::::from_flat(&bytes)?; prog.into() } else { - let code = std::fs::read_to_string(&input)?; + let code = std::fs::read_to_string(&script)?; let prog = parser::program(&code)?; Program::::try_from(prog)? }; + for arg in args { + let term: Term = parser::term(&arg)?.try_into()?; + + program = program.apply_term(&term); + } + let (term, cost, logs) = program.eval(); match term { @@ -121,7 +128,10 @@ fn main() -> anyhow::Result<()> { "\nBudget\n------\ncpu: {}\nmemory: {}\n", cost.cpu, cost.mem ); - println!("\nLogs\n----\n{}", logs.join("\n")) + + if !logs.is_empty() { + println!("\nLogs\n----\n{}", logs.join("\n")) + } } }, } diff --git a/crates/uplc/src/ast.rs b/crates/uplc/src/ast.rs index 97d84333..fd4ef74d 100644 --- a/crates/uplc/src/ast.rs +++ b/crates/uplc/src/ast.rs @@ -39,6 +39,21 @@ where term: applied_term, } } + + /// We use this to apply the validator to Datum, + /// then redeemer, then ScriptContext. If datum is + /// even necessary (i.e. minting policy). + pub fn apply_term(&self, term: &Term) -> Self { + let applied_term = Term::Apply { + function: Rc::new(self.term.clone()), + argument: Rc::new(term.clone()), + }; + + Program { + version: self.version, + term: applied_term, + } + } } impl<'a, T> Display for Program diff --git a/crates/uplc/src/parser.rs b/crates/uplc/src/parser.rs index 1bb6d5d7..80d0ef08 100644 --- a/crates/uplc/src/parser.rs +++ b/crates/uplc/src/parser.rs @@ -25,6 +25,19 @@ pub fn program(src: &str) -> Result, ParseError> { Ok(program) } +pub fn term(src: &str) -> Result, ParseError> { + // initialize the string interner to get unique name + let mut interner = Interner::new(); + + // run the generated parser + let mut term = uplc::term(src)?; + + // assign proper unique ids in place + interner.term(&mut term); + + Ok(term) +} + peg::parser! { grammar uplc() for str { pub rule program() -> Program @@ -37,7 +50,7 @@ peg::parser! { (major as usize, minor as usize, patch as usize) } - rule term() -> Term + pub rule term() -> Term = constant() / builtin() / var()