1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

pub mod util;

#[cfg(test)]
mod unit_tests;

use anyhow::Result;
use bytecode_source_map::source_map::SourceMap;
use compiled_stdlib::{stdlib_modules, StdLibOptions};
use ir_to_bytecode::{
    compiler::{compile_module, compile_script},
    parser::{parse_module, parse_script},
};
use libra_types::{account_address::AccountAddress, account_config};
use move_ir_types::location::Loc;
use std::mem;
use vm::file_format::{CompiledModule, CompiledScript};

/// An API for the compiler. Supports setting custom options.
#[derive(Clone, Debug)]
pub struct Compiler {
    /// The address used as the sender for the compiler.
    pub address: AccountAddress,
    /// Skip stdlib dependencies if true.
    pub skip_stdlib_deps: bool,
    /// Extra dependencies to compile with.
    pub extra_deps: Vec<CompiledModule>,

    // The typical way this should be used is with functional record update syntax:
    //
    // let compiler = Compiler { address, code, ..Compiler::new() };
    //
    // Until the #[non_exhaustive] attribute is available (see
    // https://github.com/rust-lang/rust/issues/44109), this workaround is required to make the
    // syntax be mandatory.
    #[allow(missing_docs)]
    #[doc(hidden)]
    pub _non_exhaustive: (),
}

impl Default for Compiler {
    fn default() -> Self {
        Self {
            address: account_config::CORE_CODE_ADDRESS,
            skip_stdlib_deps: false,
            extra_deps: vec![],
            _non_exhaustive: (),
        }
    }
}

impl Compiler {
    /// Compiles into a `CompiledScript` where the bytecode hasn't been serialized.
    pub fn into_compiled_script_and_source_map(
        mut self,
        file_name: &str,
        code: &str,
    ) -> Result<(CompiledScript, SourceMap<Loc>)> {
        let (compiled_script, source_map, _) = self.compile_script(file_name, code)?;
        Ok((compiled_script, source_map))
    }

    /// Compiles the script into a serialized form.
    pub fn into_script_blob(mut self, file_name: &str, code: &str) -> Result<Vec<u8>> {
        let compiled_script = self.compile_script(file_name, code)?.0;

        let mut serialized_script = Vec::<u8>::new();
        compiled_script.serialize(&mut serialized_script)?;
        Ok(serialized_script)
    }

    /// Compiles the module.
    pub fn into_compiled_module(mut self, file_name: &str, code: &str) -> Result<CompiledModule> {
        Ok(self.compile_mod(file_name, code)?.0)
    }

    /// Compiles the module into a serialized form.
    pub fn into_module_blob(mut self, file_name: &str, code: &str) -> Result<Vec<u8>> {
        let compiled_module = self.compile_mod(file_name, code)?.0;

        let mut serialized_module = Vec::<u8>::new();
        compiled_module.serialize(&mut serialized_module)?;
        Ok(serialized_module)
    }

    fn compile_script(
        &mut self,
        file_name: &str,
        code: &str,
    ) -> Result<(CompiledScript, SourceMap<Loc>, Vec<CompiledModule>)> {
        let parsed_script = parse_script(file_name, code)?;
        let deps = self.deps();
        let (compiled_script, source_map) = compile_script(None, parsed_script, &deps)?;
        Ok((compiled_script, source_map, deps))
    }

    fn compile_mod(
        &mut self,
        file_name: &str,
        code: &str,
    ) -> Result<(CompiledModule, SourceMap<Loc>, Vec<CompiledModule>)> {
        let parsed_module = parse_module(file_name, code)?;
        let deps = self.deps();
        let (compiled_module, source_map) = compile_module(self.address, parsed_module, &deps)?;
        Ok((compiled_module, source_map, deps))
    }

    fn deps(&mut self) -> Vec<CompiledModule> {
        let extra_deps = mem::replace(&mut self.extra_deps, vec![]);
        if self.skip_stdlib_deps {
            extra_deps
        } else {
            let mut deps: Vec<CompiledModule> = stdlib_modules(StdLibOptions::Compiled).to_vec();
            deps.extend(extra_deps);
            deps
        }
    }
}