use std::{intrinsics::unlikely, mem, time::Instant};
use gazebo::prelude::*;
pub use runtime::{
arguments::{Arguments, ParametersParser, ParametersSpec},
call_stack::CallStack,
evaluator::Evaluator,
file_loader::{FileLoader, ReturnFileLoader},
};
use crate::{
collections::symbol_map::Symbol,
environment::Globals,
eval::compiler::{
scope::{CompilerAstMap, Scope, ScopeData},
Compiler, Constants,
},
syntax::ast::AstModule,
values::{docs::DocString, Value},
};
pub(crate) mod bc;
pub(crate) mod compiler;
pub(crate) mod runtime;
pub use runtime::profile::ProfileMode;
use crate::eval::compiler::def::DefInfo;
#[cfg(test)]
mod tests;
impl<'v, 'a> Evaluator<'v, 'a> {
pub fn eval_module(&mut self, ast: AstModule, globals: &Globals) -> anyhow::Result<Value<'v>> {
let start = Instant::now();
let AstModule {
codemap,
statement,
dialect,
} = ast;
let codemap = self
.module_env
.frozen_heap()
.alloc_any_display_from_debug(codemap.dupe());
let globals = self.module_env.frozen_heap().alloc_any(globals.dupe());
let mut scope_data = ScopeData::new();
let root_scope_id = scope_data.new_scope().0;
let mut statement = statement.into_map_payload(&mut CompilerAstMap(&mut scope_data));
if let Some(docstring) = DocString::extract_raw_starlark_docstring(&statement) {
self.module_env.set_docstring(docstring)
}
let mut scope = Scope::enter_module(
self.module_env.names(),
root_scope_id,
scope_data,
&mut statement,
globals,
codemap,
&dialect,
);
scope.errors.truncate(1);
if let Some(e) = scope.errors.pop() {
return Err(e);
}
let (module_slots, scope_names, scope_data) = scope.exit_module();
let local_count = scope_names.used.len().try_into().unwrap();
self.module_env.slots().ensure_slots(module_slots);
let old_def_info = mem::replace(
&mut self.def_info,
self.module_env.frozen_heap().alloc_any(DefInfo::for_module(
codemap,
scope_names,
globals,
)),
);
self.call_stack.push(Value::new_none(), None).unwrap();
if unlikely(self.heap_or_flame_profile) {
self.heap_profile
.record_call_enter(Value::new_none(), self.heap());
self.flame_profile.record_call_enter(Value::new_none());
}
let mut compiler = Compiler {
scope_data,
locals: Vec::new(),
globals,
codemap,
constants: Constants::new(),
has_before_stmt: self.before_stmt.enabled(),
bc_profile: self.bc_profile.enabled(),
eval: self,
};
let res = compiler.eval_module(statement, local_count);
self.call_stack.pop();
if unlikely(self.heap_or_flame_profile) {
self.heap_profile.record_call_exit(self.heap());
self.flame_profile.record_call_exit();
}
self.def_info = old_def_info;
self.module_env.add_eval_duration(start.elapsed());
res.map_err(|e| e.0)
}
pub fn eval_function(
&mut self,
function: Value<'v>,
positional: &[Value<'v>],
named: &[(&str, Value<'v>)],
) -> anyhow::Result<Value<'v>> {
let names = named.map(|(s, _)| (Symbol::new(*s), self.heap().alloc_str(*s)));
let named = named.map(|x| x.1);
let params = Arguments {
pos: positional,
named: &named,
names: &names,
args: None,
kwargs: None,
};
function.invoke(¶ms, self)
}
}