use crate::builtin::*;
use crate::compiler_info::CodeArea;
use crate::globals::Globals;
use crate::value::*;
use core::panic;
use std::collections::HashMap;
use crate::compiler::{BUILTIN_STORAGE, NULL_STORAGE};
pub type StoredValue = u32;
#[derive(Debug)]
pub struct ValStorage {
pub map: HashMap<StoredValue, StoredValData>,
pub preserved_stack: Vec<Vec<StoredValue>>,
pub prev_value_count: u32,
}
#[derive(Debug, Clone)]
pub struct StoredValData {
pub val: Value,
pub fn_context: Group,
pub mutable: bool,
pub def_area: CodeArea,
marked: bool,
}
impl std::ops::Index<StoredValue> for ValStorage {
type Output = Value;
fn index(&self, i: StoredValue) -> &Self::Output {
&self
.map
.get(&i)
.unwrap_or_else(|| panic!("index {} not found", i))
.val
}
}
impl std::ops::IndexMut<StoredValue> for ValStorage {
fn index_mut(&mut self, i: StoredValue) -> &mut Self::Output {
&mut self.map.get_mut(&i).unwrap().val
}
}
impl ValStorage {
pub fn new() -> Self {
ValStorage {
map: vec![
(
BUILTIN_STORAGE,
StoredValData {
val: Value::Builtins,
fn_context: Group::new(0),
mutable: false,
def_area: CodeArea::new(),
marked: false,
},
),
(
NULL_STORAGE,
StoredValData {
val: Value::Null,
fn_context: Group::new(0),
mutable: false,
def_area: CodeArea::new(),
marked: false,
},
),
]
.iter()
.cloned()
.collect(),
preserved_stack: Vec::new(),
prev_value_count: 100,
}
}
pub fn set_mutability(&mut self, index: StoredValue, mutable: bool) {
if !mutable || !matches!(self[index], Value::Macro(_)) {
(*self.map.get_mut(&index).unwrap()).mutable = mutable;
}
match self[index].clone() {
Value::Array(a) => {
for e in a {
self.set_mutability(e, mutable);
}
}
Value::Dict(a) => {
for (_, e) in a {
self.set_mutability(e, mutable);
}
}
Value::Macro(_) => (),
_ => (),
};
}
fn marked(&self, root: StoredValue) -> bool {
self.map
.get(&root)
.unwrap_or_else(|| panic!("Could not find {}", root))
.marked
}
pub fn mark(&mut self, root: StoredValue) {
if !self.marked(root) {
(*self.map.get_mut(&root).unwrap()).marked = true;
match self[root].clone() {
Value::Array(a) => {
for e in a.iter() {
self.mark(*e)
}
}
Value::Dict(a) => {
for (_, e) in a.iter() {
self.mark(*e)
}
}
Value::Macro(m) => {
for (_, e, _, e2, _, _) in m.args {
if let Some(val) = e {
self.mark(val)
}
if let Some(val) = e2 {
self.mark(val)
}
}
for (_, v) in m.def_variables.iter() {
self.mark(*v)
}
}
_ => (),
};
}
}
pub fn sweep(&mut self) {
self.map.retain(|_, a| a.marked);
for v in self.map.values_mut() {
(*v).marked = false;
}
}
}
pub fn clone_and_get_value(
index: StoredValue,
globals: &mut Globals,
fn_context: Group,
constant: bool,
) -> Value {
let mut old_val = globals.stored_values[index].clone();
match &mut old_val {
Value::Array(arr) => {
old_val = Value::Array(
arr.iter()
.map(|x| clone_value_preserve_area(*x, globals, fn_context, constant))
.collect(),
);
}
Value::Dict(arr) => {
old_val = Value::Dict(
arr.iter()
.map(|(k, v)| {
(
*k,
clone_value_preserve_area(*v, globals, fn_context, constant),
)
})
.collect(),
);
}
Value::Macro(m) => {
for arg in &mut m.args {
if let Some(def_val) = &mut arg.1 {
(*def_val) = clone_value_preserve_area(*def_val, globals, fn_context, constant);
}
if let Some(def_val) = &mut arg.3 {
(*def_val) = clone_value_preserve_area(*def_val, globals, fn_context, constant);
}
}
}
_ => (),
};
old_val
}
pub fn clone_value(
index: StoredValue,
globals: &mut Globals,
fn_context: Group,
constant: bool,
area: CodeArea,
) -> StoredValue {
let old_val = clone_and_get_value(index, globals, fn_context, constant);
let new_index = globals.val_id;
(*globals).stored_values.map.insert(
new_index,
StoredValData {
val: old_val,
fn_context,
mutable: !constant,
def_area: area,
marked: false,
},
);
(*globals).val_id += 1;
new_index
}
pub fn clone_value_preserve_area(
index: StoredValue,
globals: &mut Globals,
fn_context: Group,
constant: bool,
) -> StoredValue {
let old_val = clone_and_get_value(index, globals, fn_context, constant);
let new_index = globals.val_id;
(*globals).stored_values.map.insert(
new_index,
StoredValData {
val: old_val,
fn_context,
mutable: !constant,
def_area: globals.get_area(index),
marked: false,
},
);
(*globals).val_id += 1;
new_index
}
pub fn store_const_value(
val: Value,
globals: &mut Globals,
fn_context: Group,
area: CodeArea,
) -> StoredValue {
let index = globals.val_id;
(*globals).stored_values.map.insert(
index,
StoredValData {
val,
fn_context,
mutable: false,
def_area: area,
marked: false,
},
);
(*globals).val_id += 1;
index
}
pub fn store_val_m(
val: Value,
globals: &mut Globals,
fn_context: Group,
constant: bool,
area: CodeArea,
) -> StoredValue {
let index = globals.val_id;
(*globals).stored_values.map.insert(
index,
StoredValData {
val,
fn_context,
mutable: !constant,
def_area: area,
marked: false,
},
);
(*globals).val_id += 1;
index
}