1use std::fmt;
5
6use elements::opcodes::{self};
7use elements::script;
8
9use super::{EvalError, TxEnv};
10use crate::expression::{FromTree, Tree};
11use crate::miniscript::lex::Token as Tk;
12use crate::{expression, script_num_size, Error};
13
14#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
17pub enum IdxExpr {
18 Const(usize),
22 CurrIdx,
24 Add(Box<IdxExpr>, Box<IdxExpr>),
27 Sub(Box<IdxExpr>, Box<IdxExpr>),
30 Mul(Box<IdxExpr>, Box<IdxExpr>),
33 Div(Box<IdxExpr>, Box<IdxExpr>),
36}
37
38impl IdxExpr {
39 pub fn script_size(&self) -> usize {
41 match self {
42 IdxExpr::Const(i) => script_num_size(*i),
43 IdxExpr::CurrIdx => 1,
44 IdxExpr::Add(x, y) => x.script_size() + y.script_size() + 1,
45 IdxExpr::Sub(x, y) => x.script_size() + y.script_size() + 1,
46 IdxExpr::Mul(x, y) => x.script_size() + y.script_size() + 6,
47 IdxExpr::Div(x, y) => x.script_size() + y.script_size() + 7,
48 }
49 }
50}
51
52impl fmt::Display for IdxExpr {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 IdxExpr::Const(i) => write!(f, "{}", i),
56 IdxExpr::CurrIdx => write!(f, "curr_idx"),
57 IdxExpr::Add(x, y) => write!(f, "idx_add({},{})", x, y),
58 IdxExpr::Sub(x, y) => write!(f, "idx_sub({},{})", x, y),
59 IdxExpr::Mul(x, y) => write!(f, "idx_mul({},{})", x, y),
60 IdxExpr::Div(x, y) => write!(f, "idx_div({},{})", x, y),
61 }
62 }
63}
64
65impl fmt::Debug for IdxExpr {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 IdxExpr::Const(i) => write!(f, "{:?}", i),
69 IdxExpr::CurrIdx => write!(f, "curr_idx"),
70 IdxExpr::Add(x, y) => write!(f, "idx_add({:?},{:?})", x, y),
71 IdxExpr::Sub(x, y) => write!(f, "idx_sub({:?},{:?})", x, y),
72 IdxExpr::Mul(x, y) => write!(f, "idx_mul({:?},{:?})", x, y),
73 IdxExpr::Div(x, y) => write!(f, "idx_div({:?},{:?})", x, y),
74 }
75 }
76}
77
78impl FromTree for IdxExpr {
79 fn from_tree(top: &Tree<'_>) -> Result<Self, Error> {
80 match (top.name, top.args.len()) {
81 ("curr_idx", 0) => Ok(IdxExpr::CurrIdx),
82 ("idx_add", 2) => Ok(IdxExpr::Add(
83 Box::new(Self::from_tree(&top.args[0])?),
84 Box::new(Self::from_tree(&top.args[1])?),
85 )),
86 ("idx_sub", 2) => Ok(IdxExpr::Sub(
87 Box::new(Self::from_tree(&top.args[0])?),
88 Box::new(Self::from_tree(&top.args[1])?),
89 )),
90 ("idx_mul", 2) => Ok(IdxExpr::Mul(
91 Box::new(Self::from_tree(&top.args[0])?),
92 Box::new(Self::from_tree(&top.args[1])?),
93 )),
94 ("idx_div", 2) => Ok(IdxExpr::Div(
95 Box::new(Self::from_tree(&top.args[0])?),
96 Box::new(Self::from_tree(&top.args[1])?),
97 )),
98 (_num, 0) => {
99 expression::terminal(top, expression::parse_num::<usize>).map(IdxExpr::Const)
100 }
101 _ => Err(Error::Unexpected(format!("Unexpected token: {:?}", top))),
102 }
103 }
104}
105
106impl IdxExpr {
107 pub fn push_to_builder(&self, builder: script::Builder) -> script::Builder {
111 use opcodes::all::*;
112 match self {
113 IdxExpr::Const(i) => builder.push_int(*i as i64),
114 IdxExpr::CurrIdx => builder.push_opcode(OP_PUSHCURRENTINPUTINDEX),
115 IdxExpr::Add(x, y) => {
116 let builder = x.push_to_builder(builder);
117 let builder = y.push_to_builder(builder);
118 builder.push_opcode(OP_ADD)
119 }
120 IdxExpr::Sub(x, y) => {
121 let builder = x.push_to_builder(builder);
122 let builder = y.push_to_builder(builder);
123 builder.push_opcode(OP_SUB)
124 }
125 IdxExpr::Mul(x, y) => {
126 let builder = x.push_to_builder(builder).push_opcode(OP_SCRIPTNUMTOLE64);
127 let builder = y.push_to_builder(builder).push_opcode(OP_SCRIPTNUMTOLE64);
128 builder
129 .push_opcode(OP_MUL64)
130 .push_int(1)
131 .push_opcode(OP_EQUALVERIFY)
132 .push_opcode(OP_LE64TOSCRIPTNUM)
133 }
134 IdxExpr::Div(x, y) => {
135 let builder = x.push_to_builder(builder).push_opcode(OP_SCRIPTNUMTOLE64);
136 let builder = y.push_to_builder(builder).push_opcode(OP_SCRIPTNUMTOLE64);
137 builder
138 .push_opcode(OP_DIV64)
139 .push_int(1)
140 .push_opcode(OP_EQUALVERIFY)
141 .push_opcode(OP_NIP)
142 .push_opcode(OP_LE64TOSCRIPTNUM)
143 }
144 }
145 }
146
147 pub fn eval(&self, env: &TxEnv) -> Result<usize, EvalError> {
149 match self {
150 IdxExpr::Const(i) => Ok(*i),
151 IdxExpr::CurrIdx => Ok(env.idx),
152 IdxExpr::Add(x, y) => Ok(x.eval(env)? + y.eval(env)?),
153 IdxExpr::Sub(x, y) => Ok(x.eval(env)? - y.eval(env)?),
154 IdxExpr::Mul(x, y) => Ok(x.eval(env)? * y.eval(env)?),
155 IdxExpr::Div(x, y) => Ok(x.eval(env)? / y.eval(env)?),
156 }
157 }
158
159 #[rustfmt::skip]
162 pub fn from_tokens(tokens: &[Tk], end_pos: usize) -> Option<(Self, usize)> {
163 let tks = tokens;
164 let e = end_pos; if let Some(&[Tk::Num(i)]) = tks.get(e.checked_sub(1)?..e) {
166 Some((IdxExpr::Const(i as usize), e - 1))
167 } else if let Some(&[Tk::CurrInp]) = tks.get(e.checked_sub(1)?..e) {
168 Some((IdxExpr::CurrIdx, e - 1))
169 } else if let Some(&[Tk::Add]) = tks.get(e.checked_sub(1)?..e) {
170 let (y, e) = IdxExpr::from_tokens(tks, e - 1)?;
171 let (x, e) = IdxExpr::from_tokens(tks, e)?;
172 Some((IdxExpr::Add(Box::new(x), Box::new(y)), e))
173 } else if let Some(&[Tk::Sub]) = tks.get(e.checked_sub(1)?..e) {
174 let (y, e) = IdxExpr::from_tokens(tks, e - 1)?;
175 let (x, e) = IdxExpr::from_tokens(tks, e)?;
176 Some((IdxExpr::Sub(Box::new(x), Box::new(y)), e))
177 } else if let Some(&[Tk::ScriptNumToLe64, Tk::Mul64, Tk::Num(1), Tk::Equal, Tk::Verify, Tk::Le64ToScriptNum]) = tks.get(e.checked_sub(6)?..e) {
178 let (y, e) = IdxExpr::from_tokens(tks, e - 6)?;
179 if let Some(&[Tk::ScriptNumToLe64]) = tks.get(e.checked_sub(1)?..e) {
180 let (x, e) = IdxExpr::from_tokens(tks, e - 1)?;
181 Some((IdxExpr::Mul(Box::new(x), Box::new(y)), e))
182 } else {
183 None
184 }
185 } else if let Some(&[Tk::ScriptNumToLe64, Tk::Div64, Tk::Num(1), Tk::Equal, Tk::Verify, Tk::Nip, Tk::Le64ToScriptNum]) = tks.get(e.checked_sub(7)?..e) {
186 let (y, e) = IdxExpr::from_tokens(tks, e - 7)?;
187 if let Some(&[Tk::ScriptNumToLe64]) = tks.get(e.checked_sub(1)?..e) {
188 let (x, e) = IdxExpr::from_tokens(tks, e - 1)?;
189 Some((IdxExpr::Div(Box::new(x), Box::new(y)), e))
190 } else {
191 None
192 }
193 } else {
194 None
195 }
196 }
197}