Implement apply evaluate
Co-authored-by: rvcas <x@rvcas.dev>
This commit is contained in:
parent
650a789194
commit
0e2214a908
|
@ -33,6 +33,13 @@ pub enum UplcCommand {
|
|||
},
|
||||
/// Format an Untyped Plutus Core program
|
||||
Fmt { input: PathBuf },
|
||||
|
||||
/// Evaluate an Untyped Plutus Core program
|
||||
Eval {
|
||||
input: PathBuf,
|
||||
#[clap(short, long)]
|
||||
flat: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for Args {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fs;
|
||||
|
||||
use uplc::{
|
||||
ast::{DeBruijn, Name, Program},
|
||||
ast::{DeBruijn, FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term},
|
||||
parser,
|
||||
};
|
||||
|
||||
|
@ -77,6 +77,27 @@ fn main() -> anyhow::Result<()> {
|
|||
fs::write(&out_name, pretty)?;
|
||||
}
|
||||
}
|
||||
UplcCommand::Eval { input, flat } => {
|
||||
let program = if flat {
|
||||
let bytes = std::fs::read(&input)?;
|
||||
|
||||
let prog = Program::<FakeNamedDeBruijn>::from_flat(&bytes)?;
|
||||
|
||||
prog.into()
|
||||
} else {
|
||||
let code = std::fs::read_to_string(&input)?;
|
||||
|
||||
let prog = parser::program(&code)?;
|
||||
|
||||
Program::<NamedDeBruijn>::try_from(prog)?
|
||||
};
|
||||
|
||||
let term = program.eval()?;
|
||||
|
||||
let term: Term<Name> = term.try_into()?;
|
||||
|
||||
println!("{}", term.to_pretty());
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::fmt::Display;
|
|||
use crate::{
|
||||
builtins::DefaultFunction,
|
||||
debruijn::{self, Converter},
|
||||
machine::{Costs, ExBudget, Machine},
|
||||
};
|
||||
|
||||
/// This represents a program in Untyped Plutus Core.
|
||||
|
@ -400,3 +401,12 @@ impl From<Term<FakeNamedDeBruijn>> for Term<NamedDeBruijn> {
|
|||
converter.fake_named_debruijn_to_named_debruijn(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Program<NamedDeBruijn> {
|
||||
pub fn eval(&self) -> Result<Term<NamedDeBruijn>, crate::machine::Error> {
|
||||
let mut machine = Machine::new(Costs::default(), ExBudget::default(), 200);
|
||||
|
||||
let (term, _, _) = machine.run(&self.term)?;
|
||||
Ok(term)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,10 +178,19 @@ impl Machine {
|
|||
|
||||
fn apply_evaluate(
|
||||
&mut self,
|
||||
_function: Value,
|
||||
_argument: Value,
|
||||
function: Value,
|
||||
argument: Value,
|
||||
) -> Result<Term<NamedDeBruijn>, Error> {
|
||||
todo!()
|
||||
match function {
|
||||
Value::Lambda { body, .. } => {
|
||||
self.env.push(argument);
|
||||
let term = self.compute(&body)?;
|
||||
self.env.pop();
|
||||
Ok(term)
|
||||
}
|
||||
Value::Builtin(_, _) => todo!(),
|
||||
rest => Err(Error::NonFunctionalApplication(rest)),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_frame(&mut self, frame: Context) {
|
||||
|
@ -262,7 +271,7 @@ pub enum Value {
|
|||
}
|
||||
|
||||
/// Can be negative
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy, Default)]
|
||||
pub struct ExBudget {
|
||||
mem: i32,
|
||||
cpu: i32,
|
||||
|
@ -307,6 +316,7 @@ impl TryFrom<u8> for StepKind {
|
|||
|
||||
/// There's no entry for Error since we'll be exiting anyway; also, what would
|
||||
/// happen if calling 'Error' caused the budget to be exceeded?
|
||||
#[derive(Default)]
|
||||
pub struct Costs {
|
||||
startup: ExBudget,
|
||||
var: ExBudget,
|
||||
|
|
|
@ -16,4 +16,6 @@ pub enum Error {
|
|||
EvaluationFailure,
|
||||
#[error("Attempted to instantiate a non-polymorphic term: {0:#?}")]
|
||||
NonPolymorphicInstantiation(Value),
|
||||
#[error("Attempted to apply a non-function: {0:#?}")]
|
||||
NonFunctionalApplication(Value),
|
||||
}
|
||||
|
|
|
@ -41,6 +41,28 @@ impl Program<Name> {
|
|||
}
|
||||
|
||||
impl Term<Name> {
|
||||
pub fn to_pretty(&self) -> String {
|
||||
let mut w = Vec::new();
|
||||
|
||||
self.to_doc().render(80, &mut w).unwrap();
|
||||
|
||||
String::from_utf8(w)
|
||||
.unwrap()
|
||||
.lines()
|
||||
// This is a hack to deal with blank newlines
|
||||
// that end up with a bunch of useless whitespace
|
||||
// because of the nesting
|
||||
.map(|l| {
|
||||
if l.chars().all(|c| c.is_whitespace()) {
|
||||
"".to_string()
|
||||
} else {
|
||||
l.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
fn to_doc(&self) -> RcDoc<()> {
|
||||
match self {
|
||||
Term::Var(name) => RcDoc::text(&name.text),
|
||||
|
|
Loading…
Reference in New Issue