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