use smallvec::{SmallVec};
use std::{usize};
use std::cell::{RefCell};
use std::collections::{HashMap, hash_map::Entry::{Occupied, Vacant}};
use std::iter::{FromIterator};
use std::rc::{Rc};
use super::{transform};
use super::ast::{Ast};
use super::code::{Bytecode, GFn, Stay};
use super::collections::{Arr, DequeAccess, DequeOps};
use super::encoder;
use super::engine::{glsp, Guard, RFn, stock_syms::*, Sym, with_vm};
use super::error::{GResult};
use super::gc::{Root, Slot};
use super::val::{Val};
use super::vm::{Frame};
use super::wrap::{CallableOps};
#[cfg(feature = "compiler")]
use super::compile::{Action};
pub(crate) fn eval(
forms: &[Val],
env_mode: Option<EnvMode>,
to_record: bool
) -> GResult<Val> {
let mut context = Context::new(env_mode);
let mut input = Vec::from_iter(forms.iter().rev().cloned());
let mut result = Ok(Val::Nil);
while let Some(form) = input.pop() {
let expanded = match fully_expand_form(&form, &mut context) {
Ok(Some(expanded)) => expanded,
Ok(None) => form,
Err(error) => {
let mut defer_result: GResult<Val> = Err(error);
context.pop_defers(&mut defer_result);
return defer_result
}
};
if expanded.is_arr() && expanded.clone().unwrap_arr().len() > 0 {
let arr = expanded.clone().unwrap_arr();
match arr.get(0)? {
Val::Sym(SPLICE_SYM) => {
input.extend(arr.iter().skip(1).rev());
}
Val::Sym(LET_MACRO_SYM) => {
result = context.push_let_macro_binding(arr).map(|_| Val::Nil);
}
Val::Sym(DEFER_SYM) => {
result = context.push_defer(arr).map(|_| Val::Nil);
}
Val::Sym(DEFER_YIELD_SYM) => {
result = Ok(Val::Nil);
}
Val::Sym(LET_SYM) => {
result = context.register_toplevel_let(arr).map(|_| Val::Nil);
}
_ => result = evaluate_form(&expanded, &context.toplevel_lets, to_record)
}
} else {
result = evaluate_form(&expanded, &context.toplevel_lets, to_record)
}
if let Err(error) = result {
let mut defer_result: GResult<Val> = Err(error);
context.pop_defers(&mut defer_result);
return defer_result
}
}
context.pop_defers(&mut result);
result
}
pub(crate) fn expand(
forms: &[Val],
env_mode: Option<EnvMode>,
collapse_splices: bool
) -> GResult<Vec<Val>> {
let mut context = Context::new(env_mode);
let mut input = Vec::from_iter(forms.iter().rev().cloned());
let mut output = Vec::<Val>::new();
while let Some(form) = input.pop() {
let expanded = fully_expand_form(&form, &mut context)?.unwrap_or(form);
if expanded.is_arr() && expanded.clone().unwrap_arr().len() > 0 {
let arr = expanded.clone().unwrap_arr();
match arr.get(0)? {
Val::Sym(SPLICE_SYM) => {
input.extend(arr.iter().skip(1).rev());
}
Val::Sym(LET_MACRO_SYM) => {
context.push_let_macro_binding(arr)?;
output.push(Val::Nil);
}
_ => output.push(expanded)
}
} else {
output.push(expanded);
}
}
if collapse_splices && output.len() != 1 {
let splice = Val::Arr(arr![SPLICE_SYM, ..output]);
output.clear();
output.push(splice);
}
Ok(output)
}
pub(crate) fn expand_1(
form: &Val,
expander: Option<Expander>,
env_mode: Option<EnvMode>
) -> GResult<Expansion> {
let mut context = Context::new(env_mode);
maybe_call_expander(form, expander, &mut context)
}
#[derive(Clone, PartialEq, Debug)]
pub enum Expansion {
ExpandedTo(Val),
MacroNoOp,
NotAMacro
}
#[derive(Clone, Debug)]
pub enum Expander {
GFn(Root<GFn>),
RFn(Root<RFn>)
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum EnvMode {
Fresh,
Copied
}
impl Default for EnvMode {
fn default() -> EnvMode {
EnvMode::Fresh
}
}
#[derive(Clone, Default)]
pub(crate) struct Env {
let_macros: RefCell<HashMap<Sym, Root<GFn>>>
}
struct Context {
toplevel_lets: HashMap<Sym, Root<Stay>>,
env: Rc<Env>,
let_stack: Vec<(Sym, Option<Root<GFn>>)>,
defers: Vec<Root<Bytecode>>
}
impl Context {
fn new(env_mode: Option<EnvMode>) -> Context {
let env = match env_mode {
None | Some(EnvMode::Fresh) => Rc::new(Env::default()),
Some(EnvMode::Copied) => {
let env = match glsp::env() {
Some(env) => (*env).clone(),
None => Env::default()
};
Rc::new(env)
}
};
Context {
toplevel_lets: HashMap::new(),
env,
let_stack: Vec::new(),
defers: Vec::new()
}
}
fn push_let_macro_binding(
&mut self,
form: Root<Arr>
) -> GResult<()> {
let span = form.span();
ensure_at!(span, form.len() >= 3, "let-macro form has too few arguments");
let name = match form.get(1)? {
Val::Sym(name) => name,
_ => bail_at!(span, "the first argument to `let-macro` must be a sym")
};
let params_arr = match form.get(2)? {
Val::Arr(arr) => arr,
_ => bail_at!(span, "the second argument to `let-macro` must be an arr")
};
let fn_arr = arr![FN_SYM, FLAG_NAME_SYM, name, params_arr];
fn_arr.set_span(span);
fn_arr.extend(form.iter().skip(3))?;
let fn_form = Val::Arr(fn_arr);
let expanded_fn = fully_expand_form(&fn_form, self)?.unwrap_or(fn_form);
let gfn = match evaluate_form(&expanded_fn, &HashMap::new(), false)? {
Val::GFn(gfn) => gfn,
_ => panic!()
};
match self.env.let_macros.borrow_mut().entry(name) {
Occupied(mut occupied) => {
let old_entry = occupied.insert(gfn);
self.let_stack.push((name, Some(old_entry)));
}
Vacant(vacant) => {
vacant.insert(gfn);
self.let_stack.push((name, None));
}
}
Ok(())
}
fn pop_binding(&mut self) {
let (name, shadowed_entry) = self.let_stack.pop().unwrap();
match self.env.let_macros.borrow_mut().entry(name) {
Occupied(mut occupied) => {
if let Some(shadowed_entry) = shadowed_entry {
occupied.insert(shadowed_entry);
} else {
occupied.remove();
}
}
Vacant(_) => panic!()
}
}
fn lookup_let_macro(&mut self, name: Sym) -> Option<Root<GFn>> {
self.env.let_macros.borrow().get(&name).cloned()
}
fn register_toplevel_let(&mut self, form: Root<Arr>) -> GResult<()> {
let span = form.span();
if form.len() != 3 {
bail_at!(span, "the (let ...) special form expects two arguments")
}
let name = match form.get::<Val>(1)? {
Val::Sym(name) => name,
_ => bail_at!(span, "(let ...) special form has invalid arguments")
};
let init_form: Val = form.get(2)?;
let stay = glsp::alloc(Stay::new(Slot::Nil));
#[cfg(feature = "compiler")]
glsp::record_action(Action::ToplevelLet(stay.clone()));
let init_val = evaluate_form(&init_form, &self.toplevel_lets, true)?;
stay.set(Slot::from_val(&init_val));
self.toplevel_lets.insert(name, stay.clone());
Ok(())
}
fn push_defer(&mut self, form: Root<Arr>) -> GResult<()> {
let do_form = arr![DO_SYM];
do_form.extend(form.iter().skip(1))?;
let mut ast = Ast::new();
let node = ast.node_from_val(&Val::Arr(do_form), glsp::generated_span())?;
transform::standard_passes(&mut ast, node);
let bytecode = encoder::encode_fragment(&ast, node, &self.toplevel_lets)?;
self.defers.push(bytecode);
Ok(())
}
fn pop_defers(&mut self, result: &mut GResult<Val>) {
for bytecode in self.defers.drain(..).rev() {
#[cfg(feature = "compiler")]
glsp::record_action(Action::Execute(bytecode.clone()));
let defer_result = with_vm(|vm| {
vm.exec_bytecode(&bytecode)
});
if let Err(error) = defer_result {
match *result {
Ok(_) => *result = Err(error),
Err(ref mut prev) => prev.chain_defer_error(error)
}
}
}
}
}
fn evaluate_form(
form: &Val,
toplevel_lets: &HashMap<Sym, Root<Stay>>,
_to_record: bool
) -> GResult<Val> {
let mut ast = Ast::new();
let node = ast.node_from_val(form, glsp::generated_span())?;
transform::standard_passes(&mut ast, node);
let bytecode = encoder::encode_fragment(&ast, node, toplevel_lets)?;
#[cfg(feature = "compiler")]
if _to_record {
glsp::record_action(Action::Execute(bytecode.clone()));
}
with_vm(|vm| {
vm.exec_bytecode(&bytecode)
})
}
fn fully_expand_form(
form: &Val,
context: &mut Context
) -> GResult<Option<Val>> {
let mut form = form.clone();
let mut form_mutated = false;
loop {
if !form.is_arr() {
return if form_mutated { Ok(Some(form)) } else { Ok(None) }
}
let mut arr = form.unwrap_arr();
if arr.len() == 0 {
return if form_mutated { Ok(Some(Val::Arr(arr))) } else { Ok(None) }
}
let mut arr_owned = false;
fn expand_element(
mut arr: Root<Arr>,
i: usize,
arr_owned: &mut bool,
context: &mut Context
) -> GResult<Root<Arr>> {
loop {
if arr.len() <= i {
return Ok(arr)
}
let elem = arr.get::<Val>(i).unwrap();
if elem.is_arr() && elem.clone().unwrap_arr().len() > 0 &&
elem.clone().unwrap_arr().get::<Val>(0).unwrap() == Val::Sym(SPLICE_SYM) {
if !*arr_owned {
arr = arr.shallow_clone();
*arr_owned = true;
}
let to_splice = elem.clone().unwrap_arr();
if to_splice.len() == 1 {
let _discarded: Val = arr.remove(i)?;
if arr.len() <= i {
return Ok(arr)
}
} else {
arr.set(i, to_splice.get::<Val>(1).unwrap())?;
for src_i in (2 .. to_splice.len()).rev() {
arr.insert(i + 1, to_splice.get::<Val>(src_i).unwrap())?;
}
}
} else {
match fully_expand_form(&elem, context)? {
Some(replacement) => {
if !*arr_owned {
arr = arr.shallow_clone();
*arr_owned = true;
}
arr.set(i, replacement)?;
}
None => return Ok(arr)
}
}
}
}
arr = expand_element(arr, 0, &mut arr_owned, context)?;
match maybe_call_expander(&Val::Arr(arr.clone()), None, context)? {
Expansion::ExpandedTo(expanded_to) => {
form = expanded_to;
form_mutated = true;
continue
}
Expansion::MacroNoOp | Expansion::NotAMacro => ()
}
fn expand_do_elements(
mut arr: Root<Arr>,
first_child_i: usize,
arr_owned: &mut bool,
context: &mut Context
) -> GResult<Root<Arr>> {
let mut let_macro_count = 0;
let mut i = first_child_i;
while i < arr.len() {
arr = expand_element(arr, i, arr_owned, context)?;
if arr.len() <= i {
break
}
if let Val::Arr(expanded_arr) = arr.get::<Val>(i)? {
if expanded_arr.len() >= 1 &&
expanded_arr.get::<Val>(0)? == Val::Sym(LET_MACRO_SYM) {
context.push_let_macro_binding(expanded_arr)?;
let_macro_count += 1;
if !*arr_owned {
arr = arr.shallow_clone();
*arr_owned = true;
}
arr.set(i, Val::Nil)?;
}
}
i += 1;
}
for _ in 0 .. let_macro_count {
context.pop_binding();
}
Ok(arr)
}
match arr.get::<Val>(0).unwrap() {
Val::Sym(QUOTE_SYM) => {
ensure_at!(arr.span(), arr.len() == 2, "invalid (quote) form passed to expander");
}
Val::Sym(SPLICE_SYM) | Val::Sym(LET_MACRO_SYM) => {
}
Val::Sym(DO_SYM) | Val::Sym(DEFER_SYM) => {
arr = expand_do_elements(arr, 1, &mut arr_owned, context)?;
}
Val::Sym(BLOCK_SYM) => {
ensure_at!(arr.span(), arr.len() >= 2, "invalid (block) form passed to expander");
arr = expand_element(arr, 1, &mut arr_owned, context)?;
arr = expand_do_elements(arr, 2, &mut arr_owned, context)?;
}
Val::Sym(FN_SYM) => {
let params_i = match arr.iter().position(|v| v.is_arr()) {
Some(i) => i,
None => bail_at!(arr.span(), "invalid (fn) form passed to expander")
};
arr = expand_do_elements(arr, params_i + 1, &mut arr_owned, context)?;
}
_ => {
let mut i = 1;
while i < arr.len() {
arr = expand_element(arr, i, &mut arr_owned, context)?;
i += 1;
}
}
}
return if arr_owned || form_mutated { Ok(Some(Val::Arr(arr))) } else { Ok(None) }
}
}
fn maybe_call_expander(
form: &Val,
expander: Option<Expander>,
context: &mut Context
) -> GResult<Expansion> {
fn invoke_macro_expander(
arr: &Root<Arr>,
overridden: bool,
expander: &Expander,
context: &mut Context
) -> GResult<Expansion> {
let prev_expanding = glsp::enter_expander(arr, Rc::clone(&context.env));
let _guard = Guard::new(|| glsp::leave_expander(prev_expanding));
let args = SmallVec::<[Val; 16]>::from_iter(arr.iter().skip(1));
let result = match expander {
Expander::RFn(ref rfn) => {
let override_name = if overridden {
Some(rfn.name())
} else {
None
};
glsp::push_frame(Frame::Expand(arr.to_raw(), override_name));
let _guard = Guard::new(|| glsp::pop_frame());
glsp::call(rfn, &args[..])
}
Expander::GFn(ref gfn) => {
let override_name = if overridden {
Some(gfn.name())
} else {
None
};
glsp::push_frame(Frame::Expand(arr.to_raw(), override_name));
let _guard = Guard::new(|| glsp::pop_frame());
glsp::call(gfn, &args[..])
}
};
match result {
Ok(val) => Ok(Expansion::ExpandedTo(val)),
Err(err) => {
if err.is_macro_no_op() {
Ok(Expansion::MacroNoOp)
} else {
Err(err)
}
}
}
}
match expander {
Some(expander) => {
ensure!(form.is_arr(), "attempted to macro-expand a form with a custom expander, \
but the form is not an arr");
let arr = form.clone().unwrap_arr();
ensure!(arr.len() > 0, "attempted to macro-expand a form with a custom expander, \
but the form is an empty arr");
ensure!(arr.get::<Val>(0)?.is_sym(), "attempted to macro-expand a form with a custom \
expander, but it doesn't start with a sym");
invoke_macro_expander(&arr, true, &expander, context)
}
None => {
match *form {
Val::Arr(ref arr) if arr.len() > 0 && arr.get::<Val>(0).unwrap().is_sym() => {
let sym = arr.get::<Sym>(0).unwrap();
if let Some(expander_gfn) = context.lookup_let_macro(sym) {
let expander = Expander::GFn(expander_gfn.clone());
return invoke_macro_expander(&arr, false, &expander, context)
}
if glsp::has_macro(sym).unwrap() {
let expander = glsp::get_macro(sym).unwrap();
return invoke_macro_expander(&arr, false, &expander, context)
}
Ok(Expansion::NotAMacro)
}
_ => Ok(Expansion::NotAMacro)
}
}
}
}