1use crate::types::ToValue;
2use anyhow::{Result, anyhow};
3use leo_ast::Location;
4use leo_ast::NetworkName;
5use leo_interpreter::{Element, Frame, FunctionVariant, Interpreter};
6use leo_parser;
7use leo_span::source_map::FileName;
8use leo_span::{SESSION_GLOBALS, SessionGlobals, Symbol, with_session_globals};
9use snarkvm::prelude::{Program, TestnetV0};
10use std::{cell::RefCell, collections::HashMap, fs, path::Path, rc::Rc};
11
12pub struct SharedInterpreterState {
13 pub interpreter: RefCell<Interpreter>,
14 pub session: SessionGlobals,
15}
16
17thread_local! {
18 static SHARED_INTERPRETER: RefCell<Option<Rc<SharedInterpreterState>>> = const { RefCell::new(None) };
19}
20
21pub fn initialize_shared_interpreter(interpreter: Interpreter, session: SessionGlobals) -> bool {
22 SHARED_INTERPRETER.with(|shared| {
23 let mut state = shared.borrow_mut();
24 if state.is_none() {
25 *state = Some(Rc::new(SharedInterpreterState {
26 interpreter: RefCell::new(interpreter),
27 session,
28 }));
29 true
30 } else {
31 false
32 }
33 })
34}
35
36pub fn with_shared_interpreter<T, F>(f: F) -> Option<T>
37where
38 F: FnOnce(&SharedInterpreterState) -> T,
39{
40 SHARED_INTERPRETER.with(|shared| {
41 shared
42 .borrow()
43 .as_ref()
44 .map(|state| SESSION_GLOBALS.set(&state.session, || f(state)))
45 })
46}
47
48pub trait InterpreterExtensions {
49 fn load_leo_program(&mut self, path: &Path) -> Result<()>;
50
51 fn load_aleo_program_from_string(&mut self, bytecode: &str) -> Result<()>;
52
53 fn is_program_loaded(&self, program_name: &str) -> bool;
54
55 fn get_loaded_programs(&self) -> Vec<String>;
56
57 fn set_signer(&mut self, signer: snarkvm::prelude::Address<TestnetV0>);
58}
59
60impl InterpreterExtensions for Interpreter {
61 fn load_leo_program(&mut self, path: &Path) -> Result<()> {
62 let text = fs::read_to_string(path)
63 .map_err(|e| anyhow!("Failed to read file {:?}: {}", path, e))?;
64 let source_file = with_session_globals(|s| {
65 s.source_map
66 .new_source(&text, FileName::Real(path.to_path_buf()))
67 });
68
69 let ast = leo_parser::parse_ast(
70 self.handler.clone(),
71 &self.node_builder,
72 &source_file,
73 &[],
74 NetworkName::TestnetV0,
75 )?;
76
77 for (&program, scope) in ast.ast.program_scopes.iter() {
78 self.filename_to_program
79 .insert(path.to_path_buf(), program.to_string());
80
81 for (name, function) in scope.functions.iter() {
82 self.cursor.functions.insert(
83 Location::new(program, vec![*name]),
84 FunctionVariant::Leo(function.clone()),
85 );
86 }
87
88 for (name, composite) in scope.structs.iter() {
89 self.cursor.structs.insert(
90 vec![*name],
91 composite
92 .members
93 .iter()
94 .map(|m| (m.identifier.name, m.type_.clone()))
95 .collect(),
96 );
97 }
98
99 for (name, _mapping) in scope.mappings.iter() {
100 self.cursor
101 .mappings
102 .insert(Location::new(program, vec![*name]), HashMap::new());
103 }
104
105 for (name, const_declaration) in scope.consts.iter() {
106 self.cursor.frames.push(Frame {
107 step: 0,
108 element: Element::Expression(
109 const_declaration.value.clone(),
110 Some(const_declaration.type_.clone()),
111 ),
112 user_initiated: false,
113 });
114 self.cursor.over()?;
115 let value = self.cursor.values.pop().unwrap();
116 self.cursor
117 .globals
118 .insert(Location::new(program, vec![*name]), value);
119 }
120 }
121
122 Ok(())
123 }
124
125 fn load_aleo_program_from_string(&mut self, bytecode: &str) -> Result<()> {
126 let aleo_program: Program<TestnetV0> = bytecode.parse()?;
127 let program = Symbol::intern(&aleo_program.id().name().to_string());
128
129 for (name, struct_type) in aleo_program.structs().iter() {
130 self.cursor.structs.insert(
131 vec![Symbol::intern(&name.to_string())],
132 struct_type
133 .members()
134 .iter()
135 .map(|(id, type_)| {
136 (
137 leo_ast::Identifier::from(id).name,
138 leo_ast::Type::from_snarkvm(type_, None),
139 )
140 })
141 .collect(),
142 );
143 }
144
145 for (name, record_type) in aleo_program.records().iter() {
146 use snarkvm::prelude::EntryType;
147 let type_name = Symbol::intern(&name.to_string());
148
149 let mut members: indexmap::IndexMap<Symbol, leo_ast::Type> = indexmap::IndexMap::new();
150
151 members.insert(Symbol::intern("owner"), leo_ast::Type::Address);
152
153 for (id, entry) in record_type.entries().iter() {
154 let inner_type = match entry {
155 EntryType::Public(t) | EntryType::Private(t) | EntryType::Constant(t) => t,
156 };
157 members.insert(
158 leo_ast::Identifier::from(id).name,
159 leo_ast::Type::from_snarkvm(inner_type, None),
160 );
161 }
162
163 self.cursor
164 .records
165 .insert((program, vec![type_name]), members);
166 }
167
168 for (name, _mapping) in aleo_program.mappings().iter() {
169 self.cursor.mappings.insert(
170 Location::new(program, vec![Symbol::intern(&name.to_string())]),
171 HashMap::new(),
172 );
173 }
174
175 for (name, function) in aleo_program.functions().iter() {
176 self.cursor.functions.insert(
177 Location::new(program, vec![Symbol::intern(&name.to_string())]),
178 FunctionVariant::AleoFunction(function.clone()),
179 );
180 }
181
182 for (name, closure) in aleo_program.closures().iter() {
183 self.cursor.functions.insert(
184 Location::new(program, vec![Symbol::intern(&name.to_string())]),
185 FunctionVariant::AleoClosure(closure.clone()),
186 );
187 }
188
189 Ok(())
190 }
191
192 fn is_program_loaded(&self, program_name: &str) -> bool {
193 let program_symbol = Symbol::intern(program_name);
194
195 self.cursor
196 .functions
197 .keys()
198 .any(|gid| gid.program == program_symbol)
199 || self
200 .cursor
201 .mappings
202 .keys()
203 .any(|gid| gid.program == program_symbol)
204 || self
205 .cursor
206 .globals
207 .keys()
208 .any(|gid| gid.program == program_symbol)
209 || self
210 .cursor
211 .records
212 .keys()
213 .any(|(p, _)| *p == program_symbol)
214 }
215
216 fn get_loaded_programs(&self) -> Vec<String> {
217 let mut programs = std::collections::HashSet::new();
218 for global_id in self.cursor.functions.keys() {
219 programs.insert(global_id.program.to_string());
220 }
221 for global_id in self.cursor.mappings.keys() {
222 programs.insert(global_id.program.to_string());
223 }
224 for global_id in self.cursor.globals.keys() {
225 programs.insert(global_id.program.to_string());
226 }
227 for (program, _) in self.cursor.records.keys() {
228 programs.insert(program.to_string());
229 }
230 programs.into_iter().collect()
231 }
232
233 fn set_signer(&mut self, signer: snarkvm::prelude::Address<TestnetV0>) {
234 self.cursor.signer = signer.to_value().into();
235 }
236}