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
123
124
125
extern crate reproto_ast as ast;
extern crate reproto_core as core;
extern crate reproto_manifest as manifest;

use core::{ContextItem, Object, RelativePath, Resolver, RpPackage, RpVersionedPackage};
use manifest::Lang;
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
use std::str;

/// Input to the compiler.
pub enum Input<'input> {
    /// Already derive file.
    File(ast::File<'input>, Option<RpVersionedPackage>),
    /// Object that should be parsed.
    Object(Box<Object>, Option<RpVersionedPackage>),
}

/// A simple compilation stage.
pub struct SimpleCompile<'input> {
    pub input: Input<'input>,
    pub package_prefix: Option<RpPackage>,
    pub resolver: Option<Box<Resolver>>,
    pub errors: Option<Rc<RefCell<Vec<ContextItem>>>>,
}

impl<'input> SimpleCompile<'input> {
    /// Build a new compilation stage.
    pub fn new(input: Input<'input>) -> SimpleCompile {
        Self {
            input: input,
            package_prefix: None,
            resolver: None,
            errors: None,
        }
    }

    /// Set package prefix.
    pub fn package_prefix(self, package: RpPackage) -> Self {
        Self {
            package_prefix: Some(package),
            ..self
        }
    }

    /// Set resolver.
    pub fn resolver(self, resolver: Box<Resolver>) -> Self {
        Self {
            resolver: Some(resolver),
            ..self
        }
    }

    /// Set a reference to collect errors.
    pub fn with_errors(self, errors: Rc<RefCell<Vec<ContextItem>>>) -> Self {
        Self {
            errors: Some(errors),
            ..self
        }
    }
}

/// Perform a simplified compilation that outputs the result into the provided Write
/// implementation.
pub fn simple_compile<O>(
    mut out: O,
    config: SimpleCompile,
    modules: Vec<Box<Any>>,
    lang: &Lang,
) -> core::errors::Result<()>
where
    O: FnMut(&RelativePath, &str) -> core::errors::Result<()>,
{
    let SimpleCompile {
        input,
        package_prefix,
        resolver,
        errors,
    } = config;

    let resolver = resolver.unwrap_or_else(|| Box::new(core::EmptyResolver));

    let capturing = core::CapturingFilesystem::new();

    let ctx = core::Context::new(capturing.filesystem());

    // Set errors reference, if configured.
    let ctx = if let Some(errors) = errors {
        ctx.with_errors(errors)
    } else {
        ctx
    };

    let ctx = Rc::new(ctx);

    let mut env = lang.into_env(ctx.clone(), package_prefix.clone(), resolver);

    match input {
        Input::File(file, package) => {
            env.import_file(file, package)?;
        }
        Input::Object(object, package) => {
            env.import_object(object.as_ref(), package)?;
        }
    }

    let preamble = manifest::ManifestPreamble::new(Some(manifest::Language::Java), None);
    let mut manifest = manifest::read_manifest(lang, preamble)?;
    manifest.modules = modules;
    manifest.package_prefix = package_prefix;

    lang.compile(ctx, env, manifest)?;

    let borrowed = capturing.files().try_borrow()?;

    let mut it = borrowed.iter().peekable();

    while let Some((path, content)) = it.next() {
        let content = str::from_utf8(content)?;
        out(path, content)?;
    }

    Ok(())
}