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
126
127
128
129
130
// Copyright 2018 The Starlark in Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Define simpler version of the evaluation function
use super::Dialect;
use super::{EvalException, FileLoader};
use crate::environment::{Environment, TypeValues};
use crate::values::*;
use codemap::CodeMap;
use codemap_diagnostic::Diagnostic;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

/// A simple FileLoader that load file from disk and cache the result in a hashmap.
#[derive(Clone)]
pub struct SimpleFileLoader {
    map: Arc<Mutex<HashMap<String, Environment>>>,
    parent_env: Environment,
    codemap: Arc<Mutex<CodeMap>>,
}

impl SimpleFileLoader {
    pub fn new(map: &Arc<Mutex<CodeMap>>, parent_env: Environment) -> SimpleFileLoader {
        SimpleFileLoader {
            map: Arc::new(Mutex::new(HashMap::new())),
            parent_env,
            codemap: map.clone(),
        }
    }
}

impl FileLoader for SimpleFileLoader {
    fn load(&self, path: &str, type_values: &TypeValues) -> Result<Environment, EvalException> {
        {
            let lock = self.map.lock().unwrap();
            if lock.contains_key(path) {
                return Ok(lock.get(path).unwrap().clone());
            }
        } // Release the lock
        let mut env = self.parent_env.child(path);
        if let Err(d) = super::eval_file(
            &self.codemap,
            path,
            Dialect::Bzl,
            &mut env,
            type_values,
            self,
        ) {
            return Err(EvalException::DiagnosedError(d));
        }
        env.freeze();
        self.map
            .lock()
            .unwrap()
            .insert(path.to_owned(), env.clone());
        Ok(env)
    }
}

/// Evaluate a string content, mutate the environment accordingly and return the evaluated value.
///
/// # Arguments
///
/// __This version uses the [`SimpleFileLoader`] implementation for
/// the file loader__
///
/// * map: the codemap object used for diagnostics
/// * path: the name of the file being evaluated, for diagnostics
/// * content: the content to evaluate
/// * dialect: Starlark language dialect
/// * env: the environment to mutate during the evaluation
pub fn eval(
    map: &Arc<Mutex<CodeMap>>,
    path: &str,
    content: &str,
    dialect: Dialect,
    env: &mut Environment,
    type_values: &TypeValues,
    file_loader_env: Environment,
) -> Result<Value, Diagnostic> {
    super::eval(
        map,
        path,
        content,
        dialect,
        env,
        type_values,
        &SimpleFileLoader::new(map, file_loader_env),
    )
}

/// Evaluate a file, mutate the environment accordingly and return the evaluated value.
///
/// __This version uses the [`SimpleFileLoader`] implementation for
/// the file loader__
///
/// # Arguments
///
/// * map: the codemap object used for diagnostics
/// * path: the file to parse and evaluate
/// * build: set to true if you want to evaluate a BUILD file or false to evaluate a .bzl file
/// * env: the environment to mutate during the evaluation
pub fn eval_file(
    map: &Arc<Mutex<CodeMap>>,
    path: &str,
    build: Dialect,
    env: &mut Environment,
    type_values: &TypeValues,
    file_loader_env: Environment,
) -> Result<Value, Diagnostic> {
    super::eval_file(
        map,
        path,
        build,
        env,
        type_values,
        &SimpleFileLoader::new(map, file_loader_env),
    )
}