1use std::io::Cursor;
8use std::path::Path;
9
10use stoffel_vm_types::compiled_binary::CompiledBinary;
11
12use crate::backend::MpcBackend;
13use crate::error::{format_compiler_errors, Error, Result};
14use crate::program::Program;
15
16#[derive(Debug, Clone, Default, PartialEq, Eq)]
17pub struct CompilationOptions {
18 pub optimize: bool,
19 pub optimization_level: u8,
20 pub print_ir: bool,
21 pub entry_points: Vec<String>,
22}
23
24pub fn compile_source(source: &str, filename: &str, backend: MpcBackend) -> Result<Program> {
25 compile_source_with_options(source, filename, backend, CompilationOptions::default())
26}
27
28pub fn compile_source_with_options(
29 source: &str,
30 filename: &str,
31 backend: MpcBackend,
32 options: CompilationOptions,
33) -> Result<Program> {
34 let options = compiler_options(backend, options);
35 let compiled = stoffellang::compile(source, filename, &options)
36 .map_err(|errors| Error::Compilation(format_compiler_errors(&errors)))?;
37 Ok(Program::new(stoffellang::convert_to_binary(&compiled)))
38}
39
40pub fn compile_file(path: &Path, backend: MpcBackend) -> Result<Program> {
41 compile_file_with_options(path, backend, CompilationOptions::default())
42}
43
44pub fn compile_file_with_options(
45 path: &Path,
46 backend: MpcBackend,
47 options: CompilationOptions,
48) -> Result<Program> {
49 let source = std::fs::read_to_string(path)?;
50 let options = compiler_options(backend, options);
51 let compiled = stoffellang::compile_file(path, &source, &options)
52 .map_err(|errors| Error::Compilation(format_compiler_errors(&errors)))?;
53 Ok(Program::new(stoffellang::convert_to_binary(&compiled)))
54}
55
56pub fn load_bytecode(bytecode: &[u8]) -> Result<Program> {
57 let mut cursor = Cursor::new(bytecode);
58 let binary = CompiledBinary::deserialize(&mut cursor)
59 .map_err(|error| Error::Bytecode(format!("{error:?}")))?;
60 if cursor.position() != bytecode.len() as u64 {
61 return Err(Error::Bytecode(format!(
62 "bytecode contains {} trailing byte(s)",
63 bytecode.len() as u64 - cursor.position()
64 )));
65 }
66 Ok(Program::new(binary))
67}
68
69fn compiler_options(
70 backend: MpcBackend,
71 options: CompilationOptions,
72) -> stoffellang::CompilerOptions {
73 let env_budget = |name: &str| std::env::var(name).ok().and_then(|v| v.parse().ok());
77 stoffellang::CompilerOptions {
78 optimize: options.optimize || options.optimization_level > 0,
79 optimization_level: options.optimization_level,
80 print_ir: options.print_ir,
81 mpc_backend: backend.compiler_backend(),
82 mpc_curve: backend.compiler_curve(),
83 entry_points: options.entry_points,
84 inline_budget: env_budget("STOFFEL_INLINE_BUDGET"),
85 unroll_budget: env_budget("STOFFEL_UNROLL_BUDGET"),
86 unroll_max_expansion: env_budget("STOFFEL_UNROLL_MAX_EXPANSION"),
87 }
88}