ezno_checker/synthesis/
mod.rs

1//! Synthesis is the aim of giving types to AST structures
2//! **Synthesis and checking are split between two passes**
3//! The aim is a AST cannot known to be valid until it everything has been attempted to be given a type
4//! Unknown types are [`types::Meta`]
5
6mod assignments;
7pub mod block;
8pub mod classes;
9pub mod declarations;
10pub mod definitions;
11pub mod expressions;
12mod extensions;
13pub mod functions;
14pub mod hoisting;
15pub mod interactive;
16pub mod interfaces;
17pub mod statements;
18pub mod type_annotations;
19pub mod variables;
20
21use block::synthesise_block;
22use parser::{
23	ASTNode, ExpressionPosition, ParseOptions, PropertyKey as ParserPropertyKey, StatementPosition,
24};
25use source_map::SourceId;
26
27use crate::{
28	context::{Environment, LocalInformation, Names, VariableRegisterArguments},
29	types::properties::PropertyKey,
30	CheckingData, Diagnostic, RootContext, TypeId, VariableId,
31};
32
33use self::{
34	declarations::synthesise_variable_declaration,
35	expressions::{synthesise_expression, synthesise_multiple_expression},
36	hoisting::hoist_variable_declaration,
37	type_annotations::synthesise_type_annotation,
38	variables::register_variable,
39};
40
41pub struct EznoParser;
42
43impl crate::ASTImplementation for EznoParser {
44	type ParseOptions = parser::ParseOptions;
45	type ParseError = (parser::ParseError, SourceId);
46	type ParserRequirements = ();
47
48	type Module<'_a> = parser::Module;
49	type OwnedModule = parser::Module;
50	type DefinitionFile<'_a> = parser::Module;
51
52	type TypeAnnotation<'_a> = parser::TypeAnnotation;
53	type TypeParameter<'_a> = parser::TypeParameter;
54	type Expression<'_a> = parser::Expression;
55	type Block<'_a> = parser::Block;
56	type MultipleExpression<'_a> = parser::expressions::MultipleExpression;
57	type ClassMethod<'_a> = parser::FunctionBase<parser::ast::ClassFunctionBase>;
58
59	type VariableField<'_a> = parser::VariableField;
60
61	type ForStatementInitiliser<'_a> = parser::statements::ForLoopStatementInitialiser;
62
63	fn module_from_string(
64		// TODO remove
65		source_id: SourceId,
66		string: String,
67		options: Self::ParseOptions,
68		_parser_requirements: &mut Self::ParserRequirements,
69	) -> Result<Self::Module<'static>, Self::ParseError> {
70		<parser::Module as parser::ASTNode>::from_string(string, options)
71			.map_err(|err| (err, source_id))
72	}
73
74	fn definition_module_from_string(
75		// TODO remove
76		source_id: SourceId,
77		string: String,
78		_parser_requirements: &mut Self::ParserRequirements,
79	) -> Result<Self::DefinitionFile<'static>, Self::ParseError> {
80		let options = ParseOptions { type_definition_module: true, ..Default::default() };
81
82		<parser::Module as parser::ASTNode>::from_string(string, options)
83			.map_err(|err| (err, source_id))
84	}
85
86	fn synthesise_module<T: crate::ReadFromFS>(
87		module: &Self::Module<'_>,
88		_source_id: SourceId,
89		module_environment: &mut Environment,
90		checking_data: &mut crate::CheckingData<T, Self>,
91	) {
92		synthesise_block(&module.items, module_environment, checking_data);
93	}
94
95	fn synthesise_definition_module<T: crate::ReadFromFS>(
96		module: &Self::DefinitionFile<'_>,
97		source: SourceId,
98		root: &RootContext,
99		checking_data: &mut CheckingData<T, Self>,
100	) -> (Names, LocalInformation) {
101		definitions::type_definition_file(module, source, checking_data, root)
102	}
103
104	fn synthesise_expression<U: crate::ReadFromFS>(
105		expression: &Self::Expression<'_>,
106		expecting: TypeId,
107		environment: &mut Environment,
108		checking_data: &mut CheckingData<U, Self>,
109	) -> TypeId {
110		synthesise_expression(expression, environment, checking_data, expecting)
111	}
112
113	fn expression_position<'_a>(expression: &'_a Self::Expression<'_a>) -> source_map::Span {
114		ASTNode::get_position(expression)
115	}
116
117	fn multiple_expression_position<'_a>(
118		expression: &'_a Self::MultipleExpression<'_a>,
119	) -> source_map::Span {
120		ASTNode::get_position(expression)
121	}
122
123	fn type_parameter_name<'_a>(parameter: &'_a Self::TypeParameter<'_a>) -> &'_a str {
124		&parameter.name
125	}
126
127	fn synthesise_type_parameter_extends<T: crate::ReadFromFS>(
128		parameter: &Self::TypeParameter<'_>,
129		environment: &mut Environment,
130		checking_data: &mut crate::CheckingData<T, Self>,
131	) -> TypeId {
132		if let Some(ref extends) = parameter.extends {
133			synthesise_type_annotation(extends, environment, checking_data)
134		} else {
135			TypeId::ANY_TYPE
136		}
137	}
138
139	fn type_annotation_position<'_a>(
140		annotation: &'_a Self::TypeAnnotation<'_a>,
141	) -> source_map::Span {
142		ASTNode::get_position(annotation)
143	}
144
145	fn synthesise_type_annotation<T: crate::ReadFromFS>(
146		annotation: &Self::TypeAnnotation<'_>,
147		environment: &mut Environment,
148		checking_data: &mut crate::CheckingData<T, Self>,
149	) -> TypeId {
150		synthesise_type_annotation(annotation, environment, checking_data)
151	}
152
153	fn parse_options(
154		is_js: bool,
155		extra_syntax: bool,
156		parse_comments: bool,
157		lsp_mode: bool,
158	) -> Self::ParseOptions {
159		parser::ParseOptions {
160			comments: if parse_comments {
161				parser::Comments::JustDocumentation
162			} else {
163				parser::Comments::None
164			},
165			type_annotations: !is_js,
166			partial_syntax: lsp_mode,
167			// TODO
168			retain_blank_lines: lsp_mode,
169			is_expressions: extra_syntax,
170			..Default::default()
171		}
172	}
173
174	fn owned_module_from_module(m: Self::Module<'static>) -> Self::OwnedModule {
175		m
176	}
177
178	fn synthesise_multiple_expression<'_a, T: crate::ReadFromFS>(
179		expression: &'_a Self::MultipleExpression<'_a>,
180		expected_type: TypeId,
181		environment: &mut Environment,
182		checking_data: &mut crate::CheckingData<T, Self>,
183	) -> TypeId {
184		synthesise_multiple_expression(expression, environment, checking_data, expected_type)
185	}
186
187	fn synthesise_for_loop_initialiser<'_a, T: crate::ReadFromFS>(
188		for_loop_initialiser: &'_a Self::ForStatementInitiliser<'_a>,
189		environment: &mut Environment,
190		checking_data: &mut crate::CheckingData<T, Self>,
191	) {
192		match for_loop_initialiser {
193			parser::statements::ForLoopStatementInitialiser::VariableDeclaration(declaration) => {
194				// TODO is this correct & the best
195				hoist_variable_declaration(declaration, environment, checking_data);
196				synthesise_variable_declaration(
197					declaration,
198					environment,
199					checking_data,
200					false,
201					// IMPORTANT!
202					checking_data.options.infer_sensible_constraints_in_for_loops,
203				);
204			}
205			parser::statements::ForLoopStatementInitialiser::VarStatement(stmt) => {
206				checking_data.raise_unimplemented_error(
207					"var in for statement initiliser",
208					stmt.get_position().with_source(environment.get_source()),
209				);
210			}
211			parser::statements::ForLoopStatementInitialiser::Expression(expr) => {
212				checking_data.raise_unimplemented_error(
213					"expression as for statement initiliser",
214					expr.get_position().with_source(environment.get_source()),
215				);
216			}
217		}
218	}
219
220	fn declare_and_assign_to_fields<'a, T: crate::ReadFromFS>(
221		field: &'a Self::VariableField<'a>,
222		environment: &mut Environment,
223		checking_data: &mut crate::CheckingData<T, Self>,
224		arguments: VariableRegisterArguments,
225	) {
226		register_variable(field, environment, checking_data, arguments);
227	}
228
229	fn parameter_constrained<'a>(parameter: &'a Self::TypeParameter<'a>) -> bool {
230		parameter.extends.is_some()
231	}
232
233	fn synthesise_block<'a, T: crate::ReadFromFS>(
234		block: &'a Self::Block<'a>,
235		environment: &mut Environment,
236		checking_data: &mut crate::CheckingData<T, Self>,
237	) {
238		synthesise_block(&block.0, environment, checking_data);
239	}
240}
241
242/// `perform_side_effect_computed` is used for hoisting
243pub(super) fn parser_property_key_to_checker_property_key<
244	P: parser::property_key::PropertyKeyKind,
245	T: crate::ReadFromFS,
246>(
247	property_key: &ParserPropertyKey<P>,
248	environment: &mut Environment,
249	checking_data: &mut CheckingData<T, EznoParser>,
250	perform_side_effect_computed: bool,
251) -> PropertyKey<'static> {
252	match property_key {
253		ParserPropertyKey::StringLiteral(value, ..) | ParserPropertyKey::Identifier(value, ..) => {
254			PropertyKey::String(std::borrow::Cow::Owned(value.clone()))
255		}
256		ParserPropertyKey::NumberLiteral(number, pos) => {
257			let result = f64::try_from(number.clone());
258			if let Ok(v) = result {
259				// TODO is there a better way
260				#[allow(clippy::float_cmp)]
261				if v.floor() == v {
262					PropertyKey::from_usize(v as usize)
263				} else {
264					// TODO
265					PropertyKey::String(std::borrow::Cow::Owned(v.to_string()))
266				}
267			} else {
268				checking_data.raise_unimplemented_error(
269					"big int as property key",
270					pos.with_source(environment.get_source()),
271				);
272				PropertyKey::Type(TypeId::UNIMPLEMENTED_ERROR_TYPE)
273			}
274		}
275		ParserPropertyKey::Computed(expression, _) => {
276			if perform_side_effect_computed {
277				let key_type =
278					synthesise_expression(expression, environment, checking_data, TypeId::ANY_TYPE);
279				PropertyKey::from_type(key_type, &checking_data.types)
280			} else {
281				PropertyKey::Type(TypeId::ANY_TYPE)
282			}
283		}
284	}
285}
286
287impl From<(parser::ParseError, SourceId)> for Diagnostic {
288	fn from(parse_error: (parser::ParseError, SourceId)) -> Self {
289		Diagnostic::Position {
290			reason: parse_error.0.reason,
291			position: parse_error.0.position.with_source(parse_error.1),
292			kind: crate::diagnostics::DiagnosticKind::Error,
293		}
294	}
295}
296
297impl crate::GenericTypeParameter for parser::TypeParameter {
298	fn get_name(&self) -> &str {
299		&self.name
300	}
301}
302
303pub trait StatementOrExpressionVariable {
304	fn get_variable_id(&self, under: SourceId) -> Option<VariableId>;
305}
306
307impl StatementOrExpressionVariable for StatementPosition {
308	fn get_variable_id(&self, under: SourceId) -> Option<VariableId> {
309		match self.identifier {
310			parser::VariableIdentifier::Standard(_, pos) => Some(VariableId(under, pos.start)),
311			parser::VariableIdentifier::Marker(_, _) => None,
312		}
313	}
314}
315
316impl StatementOrExpressionVariable for ExpressionPosition {
317	fn get_variable_id(&self, _under: SourceId) -> Option<VariableId> {
318		None
319	}
320}