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

use source_map::{SourceId, SpanWithSource};

use super::range_map::RangeMap;

use crate::{
	behavior::variables::VariableWithValue,
	types::{TypeId, TypeStore},
	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>,

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

#[derive(Debug)]
pub enum SpecialExpressions {
	CompileOut,
	Marker,
}

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

// TODO these are temp
impl TypeMappings {
	#[must_use]
	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 {
	#[must_use]
	pub fn get_variable_id(&self) -> Option<VariableId> {
		match self {
			Self::LValue(variable) => Some(variable.0.get_id()),
			Self::RValue(_) | Self::GValue(_) => None,
		}
	}

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