uplc/
ast.rs

1use crate::{
2    builtins::DefaultFunction,
3    debruijn::{self, Converter},
4    flat::Binder,
5    machine::{
6        Machine,
7        cost_model::{CostModel, ExBudget, initialize_cost_model},
8        eval_result::EvalResult,
9    },
10    optimize::interner::CodeGenInterner,
11};
12use num_bigint::BigInt;
13use num_traits::ToPrimitive;
14use pallas_addresses::{Network, ShelleyAddress, ShelleyDelegationPart, ShelleyPaymentPart};
15use pallas_primitives::{
16    alonzo::{self, Constr, PlutusData},
17    conway::{self, Language},
18};
19use pallas_traverse::ComputeHash;
20use serde::{
21    self,
22    de::{self, Deserialize, Deserializer, MapAccess, Visitor},
23    ser::{Serialize, SerializeStruct, Serializer},
24};
25use std::{
26    fmt::{self, Display},
27    hash::{self, Hash},
28    rc::Rc,
29};
30
31/// This represents a program in Untyped Plutus Core.
32/// A program contains a version tuple and a term.
33/// It is generic because Term requires a generic type.
34#[derive(Debug, Clone, PartialEq)]
35pub struct Program<T> {
36    pub version: (usize, usize, usize),
37    pub term: Term<T>,
38}
39
40impl<T> Program<T>
41where
42    T: Clone,
43{
44    /// We use this to apply the validator to Datum,
45    /// then redeemer, then ScriptContext. If datum is
46    /// even necessary (i.e. minting policy).
47    pub fn apply(&self, program: &Self) -> Self {
48        let applied_term = Term::Apply {
49            function: Rc::new(self.term.clone()),
50            argument: Rc::new(program.term.clone()),
51        };
52
53        Program {
54            version: self.version,
55            term: applied_term,
56        }
57    }
58
59    /// A convenient and faster version that `apply_term` since the program doesn't need to be
60    /// re-interned (constant Data do not introduce new bindings).
61    pub fn apply_data(&self, plutus_data: PlutusData) -> Self {
62        let applied_term = Term::Apply {
63            function: Rc::new(self.term.clone()),
64            argument: Rc::new(Term::Constant(Constant::Data(plutus_data).into())),
65        };
66
67        Program {
68            version: self.version,
69            term: applied_term,
70        }
71    }
72}
73
74impl Program<Name> {
75    /// We use this to apply the validator to Datum,
76    /// then redeemer, then ScriptContext. If datum is
77    /// even necessary (i.e. minting policy).
78    pub fn apply_term(&self, term: &Term<Name>) -> Self {
79        let applied_term = Term::Apply {
80            function: Rc::new(self.term.clone()),
81            argument: Rc::new(term.clone()),
82        };
83
84        let mut program = Program {
85            version: self.version,
86            term: applied_term,
87        };
88
89        CodeGenInterner::new().program(&mut program);
90
91        program
92    }
93
94    /// A convenient method to convery named programs to debruijn programs.
95    pub fn to_debruijn(self) -> Result<Program<DeBruijn>, debruijn::Error> {
96        self.try_into()
97    }
98
99    /// A convenient method to convery named programs to named debruijn programs.
100    pub fn to_named_debruijn(self) -> Result<Program<NamedDeBruijn>, debruijn::Error> {
101        self.try_into()
102    }
103}
104
105impl<'a, T> Display for Program<T>
106where
107    T: Binder<'a>,
108{
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        write!(f, "{}", self.to_pretty())
111    }
112}
113
114#[derive(Debug, Clone, PartialEq)]
115pub enum SerializableProgram {
116    PlutusV1Program(Program<DeBruijn>),
117    PlutusV2Program(Program<DeBruijn>),
118    PlutusV3Program(Program<DeBruijn>),
119}
120
121impl SerializableProgram {
122    pub fn inner(&self) -> &Program<DeBruijn> {
123        use SerializableProgram::*;
124
125        match self {
126            PlutusV1Program(program) => program,
127            PlutusV2Program(program) => program,
128            PlutusV3Program(program) => program,
129        }
130    }
131
132    pub fn map<F>(self, f: F) -> Self
133    where
134        F: FnOnce(Program<DeBruijn>) -> Program<DeBruijn>,
135    {
136        use SerializableProgram::*;
137
138        match self {
139            PlutusV1Program(program) => PlutusV1Program(f(program)),
140            PlutusV2Program(program) => PlutusV2Program(f(program)),
141            PlutusV3Program(program) => PlutusV3Program(f(program)),
142        }
143    }
144
145    pub fn compiled_code_and_hash(&self) -> (String, pallas_crypto::hash::Hash<28>) {
146        use SerializableProgram::*;
147
148        match self {
149            PlutusV1Program(pgrm) => {
150                let cbor = pgrm.to_cbor().unwrap();
151                let compiled_code = hex::encode(&cbor);
152                let hash = conway::PlutusScript::<1>(cbor.into()).compute_hash();
153                (compiled_code, hash)
154            }
155
156            PlutusV2Program(pgrm) => {
157                let cbor = pgrm.to_cbor().unwrap();
158                let compiled_code = hex::encode(&cbor);
159                let hash = conway::PlutusScript::<2>(cbor.into()).compute_hash();
160                (compiled_code, hash)
161            }
162
163            PlutusV3Program(pgrm) => {
164                let cbor = pgrm.to_cbor().unwrap();
165                let compiled_code = hex::encode(&cbor);
166                let hash = conway::PlutusScript::<3>(cbor.into()).compute_hash();
167                (compiled_code, hash)
168            }
169        }
170    }
171}
172
173impl Serialize for SerializableProgram {
174    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
175        let (compiled_code, hash) = self.compiled_code_and_hash();
176        let mut s = serializer.serialize_struct("Program<DeBruijn>", 2)?;
177        s.serialize_field("compiledCode", &compiled_code)?;
178        s.serialize_field("hash", &hash)?;
179        s.end()
180    }
181}
182
183impl<'a> Deserialize<'a> for SerializableProgram {
184    fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
185        #[derive(serde::Deserialize)]
186        #[serde(field_identifier, rename_all = "camelCase")]
187        enum Fields {
188            CompiledCode,
189            Hash,
190        }
191
192        struct ProgramVisitor;
193
194        impl<'a> Visitor<'a> for ProgramVisitor {
195            type Value = SerializableProgram;
196
197            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
198                formatter.write_str("validator")
199            }
200
201            fn visit_map<V>(self, mut map: V) -> Result<SerializableProgram, V::Error>
202            where
203                V: MapAccess<'a>,
204            {
205                let mut compiled_code: Option<String> = None;
206                let mut hash: Option<String> = None;
207                while let Some(key) = map.next_key()? {
208                    match key {
209                        Fields::CompiledCode => {
210                            if compiled_code.is_some() {
211                                return Err(de::Error::duplicate_field("compiledCode"));
212                            }
213                            compiled_code = Some(map.next_value()?);
214                        }
215
216                        Fields::Hash => {
217                            if hash.is_some() {
218                                return Err(de::Error::duplicate_field("hash"));
219                            }
220                            hash = Some(map.next_value()?);
221                        }
222                    }
223                }
224                let compiled_code =
225                    compiled_code.ok_or_else(|| de::Error::missing_field("compiledCode"))?;
226
227                let hash = hash.ok_or_else(|| de::Error::missing_field("hash"))?;
228
229                let mut cbor_buffer = Vec::new();
230                let mut flat_buffer = Vec::new();
231
232                Program::<DeBruijn>::from_hex(&compiled_code, &mut cbor_buffer, &mut flat_buffer)
233                    .map_err(|e| {
234                        de::Error::invalid_value(
235                            de::Unexpected::Other(&format!("{e}")),
236                            &"a base16-encoded CBOR-serialized UPLC program",
237                        )
238                    })
239                    .and_then(|program| {
240                        let cbor = || program.to_cbor().unwrap().into();
241
242                        if conway::PlutusScript::<3>(cbor()).compute_hash().to_string() == hash {
243                            return Ok(SerializableProgram::PlutusV3Program(program));
244                        }
245
246                        if conway::PlutusScript::<2>(cbor()).compute_hash().to_string() == hash {
247                            return Ok(SerializableProgram::PlutusV2Program(program));
248                        }
249
250                        if conway::PlutusScript::<1>(cbor()).compute_hash().to_string() == hash {
251                            return Ok(SerializableProgram::PlutusV1Program(program));
252                        }
253
254                        Err(de::Error::custom(
255                            "hash doesn't match any recognisable Plutus version.",
256                        ))
257                    })
258            }
259        }
260
261        const FIELDS: &[&str] = &["compiledCode", "hash"];
262        deserializer.deserialize_struct("Program<DeBruijn>", FIELDS, ProgramVisitor)
263    }
264}
265
266impl Program<DeBruijn> {
267    pub fn address(
268        &self,
269        network: Network,
270        delegation: ShelleyDelegationPart,
271        plutus_version: &Language,
272    ) -> ShelleyAddress {
273        let cbor = self.to_cbor().unwrap();
274
275        let validator_hash = match plutus_version {
276            Language::PlutusV1 => conway::PlutusScript::<1>(cbor.into()).compute_hash(),
277            Language::PlutusV2 => conway::PlutusScript::<2>(cbor.into()).compute_hash(),
278            Language::PlutusV3 => conway::PlutusScript::<3>(cbor.into()).compute_hash(),
279        };
280
281        ShelleyAddress::new(
282            network,
283            ShelleyPaymentPart::Script(validator_hash),
284            delegation,
285        )
286    }
287}
288
289/// This represents a term in Untyped Plutus Core.
290/// We need a generic type for the different forms that a program may be in.
291/// Specifically, `Var` and `parameter_name` in `Lambda` can be a `Name`,
292/// `NamedDebruijn`, or `DeBruijn`. When encoded to flat for on chain usage
293/// we must encode using the `DeBruijn` form.
294#[derive(Debug, Clone, PartialEq)]
295pub enum Term<T> {
296    // tag: 0
297    Var(Rc<T>),
298    // tag: 1
299    Delay(Rc<Term<T>>),
300    // tag: 2
301    Lambda {
302        parameter_name: Rc<T>,
303        body: Rc<Term<T>>,
304    },
305    // tag: 3
306    Apply {
307        function: Rc<Term<T>>,
308        argument: Rc<Term<T>>,
309    },
310    // tag: 4
311    Constant(Rc<Constant>),
312    // tag: 5
313    Force(Rc<Term<T>>),
314    // tag: 6
315    Error,
316    // tag: 7
317    Builtin(DefaultFunction),
318    Constr {
319        tag: usize,
320        fields: Vec<Term<T>>,
321    },
322    Case {
323        constr: Rc<Term<T>>,
324        branches: Vec<Term<T>>,
325    },
326}
327
328impl<T> Term<T> {
329    pub fn is_unit(&self) -> bool {
330        matches!(self, Term::Constant(c) if c.as_ref() == &Constant::Unit)
331    }
332
333    pub fn is_int(&self) -> bool {
334        matches!(self, Term::Constant(c) if matches!(c.as_ref(), &Constant::Integer(_)))
335    }
336}
337
338impl<T> TryInto<PlutusData> for Term<T> {
339    type Error = String;
340
341    fn try_into(self) -> Result<PlutusData, String> {
342        match self {
343            Term::Constant(rc) => match &*rc {
344                Constant::Data(data) => Ok(data.to_owned()),
345                _ => Err("not a data".to_string()),
346            },
347            _ => Err("not a data".to_string()),
348        }
349    }
350}
351
352impl<'a, T> Display for Term<T>
353where
354    T: Binder<'a>,
355{
356    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357        write!(f, "{}", self.to_pretty())
358    }
359}
360
361/// A container for the various constants that are available
362/// in Untyped Plutus Core. Used in the `Constant` variant of `Term`.
363#[derive(Debug, Clone, PartialEq)]
364pub enum Constant {
365    // tag: 0
366    Integer(BigInt),
367    // tag: 1
368    ByteString(Vec<u8>),
369    // tag: 2
370    String(String),
371    // tag: 3
372    Unit,
373    // tag: 4
374    Bool(bool),
375    // tag: 5
376    ProtoList(Type, Vec<Constant>),
377    // tag: 6
378    ProtoPair(Type, Type, Rc<Constant>, Rc<Constant>),
379    // tag: 7
380    // Apply(Box<Constant>, Type),
381    // tag: 8
382    Data(PlutusData),
383    Bls12_381G1Element(Box<blst::blst_p1>),
384    Bls12_381G2Element(Box<blst::blst_p2>),
385    Bls12_381MlResult(Box<blst::blst_fp12>),
386}
387
388pub struct Data;
389
390// TODO: See about moving these builders upstream to Pallas?
391impl Data {
392    pub fn to_hex(data: PlutusData) -> String {
393        let mut bytes = Vec::new();
394        pallas_codec::minicbor::Encoder::new(&mut bytes)
395            .encode(data)
396            .expect("failed to encode Plutus Data as cbor?");
397        hex::encode(bytes)
398    }
399    pub fn integer(i: BigInt) -> PlutusData {
400        match i.to_i128().map(|n| n.try_into()) {
401            Some(Ok(i)) => PlutusData::BigInt(alonzo::BigInt::Int(i)),
402            _ => {
403                let (sign, bytes) = i.to_bytes_be();
404                match sign {
405                    num_bigint::Sign::Minus => {
406                        PlutusData::BigInt(alonzo::BigInt::BigNInt(bytes.into()))
407                    }
408                    _ => PlutusData::BigInt(alonzo::BigInt::BigUInt(bytes.into())),
409                }
410            }
411        }
412    }
413
414    pub fn bytestring(bytes: Vec<u8>) -> PlutusData {
415        PlutusData::BoundedBytes(bytes.into())
416    }
417
418    pub fn map(kvs: Vec<(PlutusData, PlutusData)>) -> PlutusData {
419        PlutusData::Map(kvs.into())
420    }
421
422    pub fn list(xs: Vec<PlutusData>) -> PlutusData {
423        PlutusData::Array(if xs.is_empty() {
424            conway::MaybeIndefArray::Def(xs)
425        } else {
426            conway::MaybeIndefArray::Indef(xs)
427        })
428    }
429
430    pub fn constr(ix: u64, fields: Vec<PlutusData>) -> PlutusData {
431        let fields = if fields.is_empty() {
432            conway::MaybeIndefArray::Def(fields)
433        } else {
434            conway::MaybeIndefArray::Indef(fields)
435        };
436
437        // NOTE: see https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L139-L155
438        if ix < 7 {
439            PlutusData::Constr(Constr {
440                tag: 121 + ix,
441                any_constructor: None,
442                fields,
443            })
444        } else if ix < 128 {
445            PlutusData::Constr(Constr {
446                tag: 1280 + ix - 7,
447                any_constructor: None,
448                fields,
449            })
450        } else {
451            PlutusData::Constr(Constr {
452                tag: 102,
453                any_constructor: Some(ix),
454                fields,
455            })
456        }
457    }
458}
459
460#[derive(Debug, Clone, PartialEq)]
461pub enum Type {
462    Bool,
463    Integer,
464    String,
465    ByteString,
466    Unit,
467    List(Rc<Type>),
468    Pair(Rc<Type>, Rc<Type>),
469    Data,
470    Bls12_381G1Element,
471    Bls12_381G2Element,
472    Bls12_381MlResult,
473}
474
475impl Display for Type {
476    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
477        match self {
478            Type::Bool => write!(f, "bool"),
479            Type::Integer => write!(f, "integer"),
480            Type::String => write!(f, "string"),
481            Type::ByteString => write!(f, "bytestring"),
482            Type::Unit => write!(f, "unit"),
483            Type::List(t) => write!(f, "list {t}"),
484            Type::Pair(t1, t2) => write!(f, "pair {t1} {t2}"),
485            Type::Data => write!(f, "data"),
486            Type::Bls12_381G1Element => write!(f, "bls12_381_G1_element"),
487            Type::Bls12_381G2Element => write!(f, "bls12_381_G2_element"),
488            Type::Bls12_381MlResult => write!(f, "bls12_381_mlresult"),
489        }
490    }
491}
492
493/// A Name containing it's parsed textual representation
494/// and a unique id from string interning. The Name's text is
495/// interned during parsing.
496#[derive(Debug, Clone, Eq)]
497pub struct Name {
498    pub text: String,
499    pub unique: Unique,
500}
501
502impl Name {
503    pub fn text(t: impl ToString) -> Name {
504        Name {
505            text: t.to_string(),
506            unique: 0.into(),
507        }
508    }
509}
510
511impl hash::Hash for Name {
512    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
513        self.text.hash(state);
514        self.unique.hash(state);
515    }
516}
517
518impl PartialEq for Name {
519    fn eq(&self, other: &Self) -> bool {
520        self.unique == other.unique && self.text == other.text
521    }
522}
523
524/// A unique id used for string interning.
525#[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)]
526pub struct Unique(isize);
527
528impl Unique {
529    /// Create a new unique id.
530    pub fn new(unique: isize) -> Self {
531        Unique(unique)
532    }
533
534    /// Increment the available unique id. This is used during
535    /// string interning to get the next available unique id.
536    pub fn increment(&mut self) {
537        self.0 += 1;
538    }
539}
540
541impl From<isize> for Unique {
542    fn from(i: isize) -> Self {
543        Unique(i)
544    }
545}
546
547impl From<Unique> for isize {
548    fn from(d: Unique) -> Self {
549        d.0
550    }
551}
552
553impl Display for Unique {
554    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
555        write!(f, "{}", self.0)
556    }
557}
558
559/// Similar to `Name` but for Debruijn indices.
560/// `Name` is replaced by `NamedDebruijn` when converting
561/// program to it's debruijn form.
562#[derive(Debug, Clone, Eq)]
563pub struct NamedDeBruijn {
564    pub text: String,
565    pub index: DeBruijn,
566}
567
568impl PartialEq for NamedDeBruijn {
569    fn eq(&self, other: &Self) -> bool {
570        self.index == other.index
571    }
572}
573
574/// This is useful for decoding a on chain program into debruijn form.
575/// It allows for injecting fake textual names while also using Debruijn for decoding
576/// without having to loop through twice.
577#[derive(Debug, Clone)]
578pub struct FakeNamedDeBruijn(pub(crate) NamedDeBruijn);
579
580impl From<DeBruijn> for FakeNamedDeBruijn {
581    fn from(d: DeBruijn) -> Self {
582        FakeNamedDeBruijn(d.into())
583    }
584}
585
586impl From<FakeNamedDeBruijn> for DeBruijn {
587    fn from(d: FakeNamedDeBruijn) -> Self {
588        d.0.into()
589    }
590}
591
592impl From<FakeNamedDeBruijn> for NamedDeBruijn {
593    fn from(d: FakeNamedDeBruijn) -> Self {
594        d.0
595    }
596}
597
598impl From<NamedDeBruijn> for FakeNamedDeBruijn {
599    fn from(d: NamedDeBruijn) -> Self {
600        FakeNamedDeBruijn(d)
601    }
602}
603
604/// Represents a debruijn index.
605#[derive(Debug, Clone, PartialEq, Eq, Copy)]
606pub struct DeBruijn(usize);
607
608impl DeBruijn {
609    /// Create a new debruijn index.
610    pub fn new(index: usize) -> Self {
611        DeBruijn(index)
612    }
613
614    pub fn inner(&self) -> usize {
615        self.0
616    }
617}
618
619impl From<usize> for DeBruijn {
620    fn from(i: usize) -> Self {
621        DeBruijn(i)
622    }
623}
624
625impl From<DeBruijn> for usize {
626    fn from(d: DeBruijn) -> Self {
627        d.0
628    }
629}
630
631impl Display for DeBruijn {
632    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
633        write!(f, "{}", self.0)
634    }
635}
636
637impl From<NamedDeBruijn> for DeBruijn {
638    fn from(n: NamedDeBruijn) -> Self {
639        n.index
640    }
641}
642
643impl From<DeBruijn> for NamedDeBruijn {
644    fn from(index: DeBruijn) -> Self {
645        NamedDeBruijn {
646            // Inject fake name. We got `i` from the Plutus code base.
647            text: String::from("i"),
648            index,
649        }
650    }
651}
652
653/// Convert a Parsed `Program` to a `Program` in `NamedDebruijn` form.
654/// This checks for any Free Uniques in the `Program` and returns an error if found.
655impl TryFrom<Program<Name>> for Program<NamedDeBruijn> {
656    type Error = debruijn::Error;
657
658    fn try_from(value: Program<Name>) -> Result<Self, Self::Error> {
659        Ok(Program::<NamedDeBruijn> {
660            version: value.version,
661            term: value.term.try_into()?,
662        })
663    }
664}
665
666/// Convert a Parsed `Term` to a `Term` in `NamedDebruijn` form.
667/// This checks for any Free Uniques in the `Term` and returns an error if found.
668impl TryFrom<Term<Name>> for Term<NamedDeBruijn> {
669    type Error = debruijn::Error;
670
671    fn try_from(value: Term<Name>) -> Result<Self, debruijn::Error> {
672        let mut converter = Converter::new();
673
674        let term = converter.name_to_named_debruijn(&value)?;
675
676        Ok(term)
677    }
678}
679
680/// Convert a Parsed `Program` to a `Program` in `Debruijn` form.
681/// This checks for any Free Uniques in the `Program` and returns an error if found.
682impl TryFrom<Program<Name>> for Program<DeBruijn> {
683    type Error = debruijn::Error;
684
685    fn try_from(value: Program<Name>) -> Result<Self, Self::Error> {
686        Ok(Program::<DeBruijn> {
687            version: value.version,
688            term: value.term.try_into()?,
689        })
690    }
691}
692
693/// Convert a Parsed `Term` to a `Term` in `Debruijn` form.
694/// This checks for any Free Uniques in the `Program` and returns an error if found.
695impl TryFrom<Term<Name>> for Term<DeBruijn> {
696    type Error = debruijn::Error;
697
698    fn try_from(value: Term<Name>) -> Result<Self, debruijn::Error> {
699        let mut converter = Converter::new();
700
701        let term = converter.name_to_debruijn(&value)?;
702
703        Ok(term)
704    }
705}
706
707impl TryFrom<&Program<DeBruijn>> for Program<Name> {
708    type Error = debruijn::Error;
709
710    fn try_from(value: &Program<DeBruijn>) -> Result<Self, Self::Error> {
711        Ok(Program::<Name> {
712            version: value.version,
713            term: (&value.term).try_into()?,
714        })
715    }
716}
717
718impl TryFrom<&Term<DeBruijn>> for Term<Name> {
719    type Error = debruijn::Error;
720
721    fn try_from(value: &Term<DeBruijn>) -> Result<Self, debruijn::Error> {
722        let mut converter = Converter::new();
723
724        let term = converter.debruijn_to_name(value)?;
725
726        Ok(term)
727    }
728}
729
730impl TryFrom<Program<NamedDeBruijn>> for Program<Name> {
731    type Error = debruijn::Error;
732
733    fn try_from(value: Program<NamedDeBruijn>) -> Result<Self, Self::Error> {
734        Ok(Program::<Name> {
735            version: value.version,
736            term: value.term.try_into()?,
737        })
738    }
739}
740
741impl TryFrom<Term<NamedDeBruijn>> for Term<Name> {
742    type Error = debruijn::Error;
743
744    fn try_from(value: Term<NamedDeBruijn>) -> Result<Self, debruijn::Error> {
745        let mut converter = Converter::new();
746
747        let term = converter.named_debruijn_to_name(&value)?;
748
749        Ok(term)
750    }
751}
752
753impl From<Program<NamedDeBruijn>> for Program<DeBruijn> {
754    fn from(value: Program<NamedDeBruijn>) -> Self {
755        Program::<DeBruijn> {
756            version: value.version,
757            term: value.term.into(),
758        }
759    }
760}
761
762impl From<Term<NamedDeBruijn>> for Term<DeBruijn> {
763    fn from(value: Term<NamedDeBruijn>) -> Self {
764        let mut converter = Converter::new();
765
766        converter.named_debruijn_to_debruijn(&value)
767    }
768}
769
770impl From<Program<NamedDeBruijn>> for Program<FakeNamedDeBruijn> {
771    fn from(value: Program<NamedDeBruijn>) -> Self {
772        Program::<FakeNamedDeBruijn> {
773            version: value.version,
774            term: value.term.into(),
775        }
776    }
777}
778
779impl From<Term<NamedDeBruijn>> for Term<FakeNamedDeBruijn> {
780    fn from(value: Term<NamedDeBruijn>) -> Self {
781        let mut converter = Converter::new();
782
783        converter.named_debruijn_to_fake_named_debruijn(&value)
784    }
785}
786
787impl TryFrom<Program<DeBruijn>> for Program<Name> {
788    type Error = debruijn::Error;
789
790    fn try_from(value: Program<DeBruijn>) -> Result<Self, Self::Error> {
791        Ok(Program::<Name> {
792            version: value.version,
793            term: value.term.try_into()?,
794        })
795    }
796}
797
798impl TryFrom<Term<DeBruijn>> for Term<Name> {
799    type Error = debruijn::Error;
800
801    fn try_from(value: Term<DeBruijn>) -> Result<Self, debruijn::Error> {
802        let mut converter = Converter::new();
803
804        let term = converter.debruijn_to_name(&value)?;
805
806        Ok(term)
807    }
808}
809
810impl From<Program<DeBruijn>> for Program<NamedDeBruijn> {
811    fn from(value: Program<DeBruijn>) -> Self {
812        Program::<NamedDeBruijn> {
813            version: value.version,
814            term: value.term.into(),
815        }
816    }
817}
818
819impl From<Term<DeBruijn>> for Term<NamedDeBruijn> {
820    fn from(value: Term<DeBruijn>) -> Self {
821        let mut converter = Converter::new();
822
823        converter.debruijn_to_named_debruijn(&value)
824    }
825}
826
827impl From<Program<FakeNamedDeBruijn>> for Program<NamedDeBruijn> {
828    fn from(value: Program<FakeNamedDeBruijn>) -> Self {
829        Program::<NamedDeBruijn> {
830            version: value.version,
831            term: value.term.into(),
832        }
833    }
834}
835
836impl From<Term<FakeNamedDeBruijn>> for Term<NamedDeBruijn> {
837    fn from(value: Term<FakeNamedDeBruijn>) -> Self {
838        let mut converter = Converter::new();
839
840        converter.fake_named_debruijn_to_named_debruijn(&value)
841    }
842}
843
844impl Program<NamedDeBruijn> {
845    pub fn eval(self, initial_budget: ExBudget) -> EvalResult {
846        let mut machine = Machine::new(
847            Language::PlutusV3,
848            CostModel::default(),
849            initial_budget,
850            200,
851        );
852
853        let term = machine.run(self.term);
854
855        EvalResult::new(
856            term,
857            machine.ex_budget,
858            initial_budget,
859            machine.traces,
860            machine.spend_counter.map(|i| i.into()),
861        )
862    }
863
864    /// Evaluate a Program as a specific PlutusVersion
865    pub fn eval_version(self, initial_budget: ExBudget, version: &Language) -> EvalResult {
866        let mut machine = Machine::new(version.clone(), CostModel::default(), initial_budget, 200);
867
868        let term = machine.run(self.term);
869
870        EvalResult::new(
871            term,
872            machine.ex_budget,
873            initial_budget,
874            machine.traces,
875            machine.spend_counter.map(|i| i.into()),
876        )
877    }
878
879    pub fn eval_as(
880        self,
881        version: &Language,
882        costs: &[i64],
883        initial_budget: Option<&ExBudget>,
884    ) -> EvalResult {
885        let budget = initial_budget.copied().unwrap_or_default();
886
887        let mut machine = Machine::new(
888            version.clone(),
889            initialize_cost_model(version, costs),
890            budget,
891            200, //slippage
892        );
893
894        let term = machine.run(self.term);
895
896        EvalResult::new(
897            term,
898            machine.ex_budget,
899            budget,
900            machine.traces,
901            machine.spend_counter.map(|i| i.into()),
902        )
903    }
904
905    pub fn eval_debug(self, initial_budget: ExBudget, version: &Language) -> EvalResult {
906        let mut machine = Machine::new_debug(
907            version.clone(),
908            CostModel::default(),
909            initial_budget,
910            200, //slippage
911        );
912
913        let term = machine.run(self.term);
914
915        EvalResult::new(
916            term,
917            machine.ex_budget,
918            initial_budget,
919            machine.traces,
920            machine.spend_counter.map(|i| i.into()),
921        )
922    }
923}
924
925impl Program<DeBruijn> {
926    pub fn eval(&self, initial_budget: ExBudget) -> EvalResult {
927        let program: Program<NamedDeBruijn> = self.clone().into();
928        program.eval(initial_budget)
929    }
930
931    pub fn eval_version(self, initial_budget: ExBudget, version: &Language) -> EvalResult {
932        let program: Program<NamedDeBruijn> = self.clone().into();
933        program.eval_version(initial_budget, version)
934    }
935}
936
937impl Term<NamedDeBruijn> {
938    pub fn is_valid_script_result(&self) -> bool {
939        !matches!(self, Term::Error)
940    }
941}