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#[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 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 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 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 pub fn to_debruijn(self) -> Result<Program<DeBruijn>, debruijn::Error> {
96 self.try_into()
97 }
98
99 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#[derive(Debug, Clone, PartialEq)]
295pub enum Term<T> {
296 Var(Rc<T>),
298 Delay(Rc<Term<T>>),
300 Lambda {
302 parameter_name: Rc<T>,
303 body: Rc<Term<T>>,
304 },
305 Apply {
307 function: Rc<Term<T>>,
308 argument: Rc<Term<T>>,
309 },
310 Constant(Rc<Constant>),
312 Force(Rc<Term<T>>),
314 Error,
316 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#[derive(Debug, Clone, PartialEq)]
364pub enum Constant {
365 Integer(BigInt),
367 ByteString(Vec<u8>),
369 String(String),
371 Unit,
373 Bool(bool),
375 ProtoList(Type, Vec<Constant>),
377 ProtoPair(Type, Type, Rc<Constant>, Rc<Constant>),
379 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
390impl 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 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#[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#[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)]
526pub struct Unique(isize);
527
528impl Unique {
529 pub fn new(unique: isize) -> Self {
531 Unique(unique)
532 }
533
534 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#[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#[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#[derive(Debug, Clone, PartialEq, Eq, Copy)]
606pub struct DeBruijn(usize);
607
608impl DeBruijn {
609 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 text: String::from("i"),
648 index,
649 }
650 }
651}
652
653impl 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
666impl 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
680impl 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
693impl 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 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, );
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, );
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}