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
use std::{
	collections::{HashMap, HashSet},
	path::PathBuf,
};

use source_map::{SourceId, Span, SpanWithSource};

use super::range_map::RangeMap;

use crate::{
	structures::variables::VariableWithValue,
	types::{TypeId, TypeStore},
	FunctionId, GeneralContext, VariableId,
};
/// [TypeMappings] is used to retaining information between passes, including the synthesise and checking passes
/// This for use in the both use in the compiler and compiler plugins
/// Checking things are held on [crate::Memory], function things are held on [crate::HoistedFunctionContainer]
/// and module things on [crate::ModuleData]
#[derive(Default, Debug)]
pub struct TypeMappings {
	/// Figures out the types of the expressions in the AST
	pub expressions_to_instances: RangeMap<Instance>,
	/// [Variable] data to a AST mapping
	pub variables_to_constraints: VariablesToTypes,
	/// Property to type, TODO kind of temp
	pub properties_to_types: RangeMap<TypeId>,
	/// Data to a AST mapping. For classes this points to the shape
	pub types_to_types: RangeMap<TypeId>,
	pub import_statements_to_pointing_path: RangeMap<PathBuf>,
	/// can be used for tree shaking
	pub called_functions: HashSet<FunctionId>,

	/// Variable restriction. Cached after hoisting pass. TODO temp needs tidy
	pub variable_restrictions: HashMap<(SourceId, u32), (TypeId, SpanWithSource)>,
}

#[derive(Default, Debug)]
pub struct VariablesToTypes(pub(crate) HashMap<VariableId, TypeId>);

// TODO these are temp
impl TypeMappings {
	pub fn print_called_functions(&self, source: &str) -> String {
		let mut buf = "Called functions:\n".to_owned();
		for func_id in self.called_functions.iter() {
			buf.push_str(
				source.get((func_id.1 as usize)..(func_id.1 as usize + 10)).unwrap_or_default(),
			);
			buf.push('\n')
		}
		buf
	}

	pub fn print_type_mappings(
		&self,
		source: &str,
		env: &GeneralContext,
		types: &TypeStore,
	) -> String {
		todo!()
		// let mut buf = "Expression type mappings:\n".to_owned();
		// for (pos, instance) in self.expressions_to_instances.iter() {
		// 	buf.push_str(
		// 		source.get((pos.0.start as usize)..(pos.0.end as usize)).unwrap_or_default(),
		// 	);
		// 	buf.push_str(" has type ");
		// 	buf.push_str(&print_type(types, instance.get_value(), env));
		// 	buf.push('\n')
		// }
		// buf
	}
}

/// See https://www.internalpointers.com/post/understanding-meaning-lexpressions-and-rexpressions-c for a understanding
/// of LValue vs RValue
#[derive(Clone, Debug)]
pub enum Instance {
	LValue(VariableWithValue),
	RValue(TypeId),
	/// Result FROM getter
	GValue(TypeId),
}

impl Instance {
	pub fn get_variable_id(&self) -> Option<VariableId> {
		match self {
			Self::LValue(variable) => Some(variable.0.get_id()),
			Self::RValue(_) | Self::GValue(_) => None,
		}
	}

	pub fn get_value(&self) -> TypeId {
		match self {
			Instance::LValue(l) => l.1,
			Instance::GValue(value) | Instance::RValue(value) => *value,
		}
	}
}