penne/
common.rs

1//
2// Part of penne
3// Copyright (c) 2020 Sander in 't Veld
4// License: MIT
5//
6
7//! Most compiler stages share a common AST.
8
9use enumset::{EnumSet, EnumSetType};
10
11pub use crate::error::{Poison, Poisonable};
12pub use crate::lexer::Location;
13
14use crate::value_type;
15
16pub type ValueType = value_type::ValueType<Identifier>;
17
18#[must_use]
19#[derive(Debug, Clone)]
20pub enum Declaration
21{
22	Constant
23	{
24		name: Identifier,
25		value: Expression,
26		value_type: Poisonable<ValueType>,
27		flags: EnumSet<DeclarationFlag>,
28		depth: Option<Poisonable<u32>>,
29		location_of_declaration: Location,
30		location_of_type: Location,
31	},
32	Function
33	{
34		name: Identifier,
35		parameters: Vec<Parameter>,
36		body: Poisonable<FunctionBody>,
37		return_type: Poisonable<ValueType>,
38		flags: EnumSet<DeclarationFlag>,
39		location_of_declaration: Location,
40		location_of_return_type: Location,
41	},
42	FunctionHead
43	{
44		name: Identifier,
45		parameters: Vec<Parameter>,
46		return_type: Poisonable<ValueType>,
47		flags: EnumSet<DeclarationFlag>,
48		location_of_declaration: Location,
49		location_of_return_type: Location,
50	},
51	Structure
52	{
53		name: Identifier,
54		members: Vec<Member>,
55		structural_type: Poisonable<ValueType>,
56		flags: EnumSet<DeclarationFlag>,
57		depth: Option<Poisonable<u32>>,
58		location_of_declaration: Location,
59	},
60	Import
61	{
62		filename: String,
63		location: Location,
64	},
65	Poison(Poison),
66}
67
68#[must_use]
69#[derive(EnumSetType, Debug)]
70pub enum DeclarationFlag
71{
72	Public,
73	External,
74	Main,
75}
76
77#[must_use]
78#[derive(Debug, Clone)]
79pub struct Member
80{
81	pub name: Poisonable<Identifier>,
82	pub value_type: Poisonable<ValueType>,
83	pub location_of_type: Location,
84}
85
86#[must_use]
87#[derive(Debug, Clone)]
88pub struct Parameter
89{
90	pub name: Poisonable<Identifier>,
91	pub value_type: Poisonable<ValueType>,
92	pub location_of_type: Location,
93}
94
95#[must_use]
96#[derive(Debug, Clone)]
97pub struct FunctionBody
98{
99	pub statements: Vec<Statement>,
100	pub return_value: Option<Expression>,
101	pub return_value_identifier: Identifier,
102}
103
104#[must_use]
105#[derive(Debug, Clone)]
106pub struct Block
107{
108	pub statements: Vec<Statement>,
109	pub location: Location,
110}
111
112#[must_use]
113#[derive(Debug, Clone)]
114pub enum Statement
115{
116	Declaration
117	{
118		name: Identifier,
119		value: Option<Expression>,
120		value_type: Option<Poisonable<ValueType>>,
121		location: Location,
122	},
123	Assignment
124	{
125		reference: Reference,
126		value: Expression,
127		location: Location,
128	},
129	MethodCall
130	{
131		name: Identifier,
132		arguments: Vec<Expression>,
133	},
134	Loop
135	{
136		location: Location,
137	},
138	Goto
139	{
140		label: Identifier,
141		location: Location,
142	},
143	Label
144	{
145		label: Identifier,
146		location: Location,
147	},
148	If
149	{
150		condition: Comparison,
151		then_branch: Box<Statement>,
152		else_branch: Option<Else>,
153		location: Location,
154	},
155	Block(Block),
156	Poison(Poison),
157}
158
159impl Statement
160{
161	pub fn location(&self) -> &Location
162	{
163		match self
164		{
165			Statement::Declaration { location, .. } => location,
166			Statement::Assignment { location, .. } => location,
167			Statement::MethodCall { name, .. } => &name.location,
168			Statement::Loop { location } => location,
169			Statement::Goto { location, .. } => location,
170			Statement::Label { location, .. } => location,
171			Statement::If { location, .. } => location,
172			Statement::Block(block) => &block.location,
173			Statement::Poison(Poison::Error { .. }) => unreachable!(),
174			Statement::Poison(Poison::Poisoned) => unreachable!(),
175		}
176	}
177}
178
179#[must_use]
180#[derive(Debug, Clone)]
181pub struct Else
182{
183	pub branch: Box<Statement>,
184	pub location_of_else: Location,
185}
186
187#[must_use]
188#[derive(Debug, Clone)]
189pub struct Comparison
190{
191	pub op: ComparisonOp,
192	pub left: Expression,
193	pub right: Expression,
194	pub location: Location,
195	pub location_of_op: Location,
196}
197
198#[must_use]
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200pub enum ComparisonOp
201{
202	Equals,
203	DoesNotEqual,
204	IsGreater,
205	IsGE,
206	IsLess,
207	IsLE,
208}
209
210#[must_use]
211#[derive(Debug, Clone)]
212pub struct Array
213{
214	pub elements: Vec<Expression>,
215	pub location: Location,
216	pub resolution_id: u32,
217}
218
219impl Array
220{
221	pub fn get_identifier(&self) -> Identifier
222	{
223		Identifier {
224			name: "(array)".to_string(),
225			location: self.location.clone(),
226			resolution_id: self.resolution_id,
227			is_authoritative: true,
228		}
229	}
230}
231
232#[must_use]
233#[derive(Debug, Clone)]
234pub struct MemberExpression
235{
236	pub name: Poisonable<Identifier>,
237	pub offset: Option<usize>,
238	pub expression: Expression,
239}
240
241#[must_use]
242#[derive(Debug, Clone)]
243pub enum Expression
244{
245	Binary
246	{
247		op: BinaryOp,
248		left: Box<Expression>,
249		right: Box<Expression>,
250		location: Location,
251		location_of_op: Location,
252	},
253	Unary
254	{
255		op: UnaryOp,
256		expression: Box<Expression>,
257		location: Location,
258		location_of_op: Location,
259	},
260	PrimitiveLiteral
261	{
262		literal: PrimitiveLiteral,
263		location: Location,
264	},
265	NakedIntegerLiteral
266	{
267		value: i128,
268		value_type: Option<Poisonable<ValueType>>,
269		location: Location,
270	},
271	BitIntegerLiteral
272	{
273		value: u64,
274		value_type: Option<Poisonable<ValueType>>,
275		location: Location,
276	},
277	StringLiteral
278	{
279		bytes: Vec<u8>,
280		location: Location,
281	},
282	ArrayLiteral
283	{
284		array: Array,
285		element_type: Option<Poisonable<ValueType>>,
286	},
287	Structural
288	{
289		members: Vec<MemberExpression>,
290		structural_type: Poisonable<ValueType>,
291		location: Location,
292	},
293	Parenthesized
294	{
295		inner: Box<Expression>,
296		location: Location,
297	},
298	Deref
299	{
300		reference: Reference,
301		deref_type: Option<Poisonable<ValueType>>,
302	},
303	Autocoerce
304	{
305		expression: Box<Expression>,
306		coerced_type: ValueType,
307	},
308	PrimitiveCast
309	{
310		expression: Box<Expression>,
311		coerced_type: ValueType,
312		location: Location,
313		location_of_type: Location,
314	},
315	LengthOfArray
316	{
317		reference: Reference,
318		location: Location,
319	},
320	SizeOfStructure
321	{
322		name: Identifier,
323		location: Location,
324	},
325	FunctionCall
326	{
327		name: Identifier,
328		arguments: Vec<Expression>,
329		return_type: Option<Poisonable<ValueType>>,
330	},
331	Poison(Poison),
332}
333
334impl Expression
335{
336	pub fn location(&self) -> &Location
337	{
338		match self
339		{
340			Expression::Binary { location, .. } => location,
341			Expression::Unary { location, .. } => location,
342			Expression::PrimitiveLiteral { location, .. } => location,
343			Expression::NakedIntegerLiteral { location, .. } => location,
344			Expression::BitIntegerLiteral { location, .. } => location,
345			Expression::StringLiteral { location, .. } => location,
346			Expression::ArrayLiteral { array, .. } => &array.location,
347			Expression::Structural { location, .. } => location,
348			Expression::Parenthesized { location, .. } => location,
349			Expression::Deref { reference, .. } => &reference.location,
350			Expression::Autocoerce { expression, .. } => expression.location(),
351			Expression::PrimitiveCast { location, .. } => location,
352			Expression::LengthOfArray { location, .. } => &location,
353			Expression::SizeOfStructure { location, .. } => &location,
354			Expression::FunctionCall { name, .. } => &name.location,
355			Expression::Poison(Poison::Error { .. }) => unreachable!(),
356			Expression::Poison(Poison::Poisoned) => unreachable!(),
357		}
358	}
359}
360
361#[must_use]
362#[derive(Debug, Clone, Copy, PartialEq, Eq)]
363pub enum BinaryOp
364{
365	Add,
366	Subtract,
367	Multiply,
368	Divide,
369	Modulo,
370	BitwiseAnd,
371	BitwiseOr,
372	BitwiseXor,
373	ShiftLeft,
374	ShiftRight,
375}
376
377#[must_use]
378#[derive(Debug, Clone, Copy, PartialEq, Eq)]
379pub enum UnaryOp
380{
381	Negative,
382	BitwiseComplement,
383}
384
385#[must_use]
386#[derive(Debug, Clone, PartialEq, Eq)]
387pub enum PrimitiveLiteral
388{
389	Int8(i8),
390	Int16(i16),
391	Int32(i32),
392	Int64(i64),
393	Int128(i128),
394	Uint8(u8),
395	Uint16(u16),
396	Uint32(u32),
397	Uint64(u64),
398	Uint128(u128),
399	Usize(usize),
400	Bool(bool),
401}
402
403#[must_use]
404#[derive(Debug, Clone)]
405pub enum DesliceOffset
406{
407	// 0
408	ArrayByView,
409	ArrayByPointer,
410	// 1
411	Length,
412}
413
414#[must_use]
415#[derive(Debug, Clone)]
416pub enum ReferenceStep
417{
418	Element
419	{
420		argument: Box<Expression>,
421		is_endless: Option<bool>,
422	},
423	Member
424	{
425		member: Identifier,
426		offset: Option<usize>,
427	},
428	Autodeslice
429	{
430		offset: DesliceOffset,
431	},
432	Autoderef,
433	Autoview,
434}
435
436impl ReferenceStep
437{
438	pub fn is_concrete(&self) -> bool
439	{
440		match self
441		{
442			ReferenceStep::Element {
443				argument: _,
444				is_endless,
445			} => is_endless.is_some(),
446			ReferenceStep::Member { member: _, offset } => offset.is_some(),
447			ReferenceStep::Autodeslice { offset: _ } => true,
448			ReferenceStep::Autoderef => true,
449			ReferenceStep::Autoview => true,
450		}
451	}
452
453	pub fn get_member(&self) -> Option<Identifier>
454	{
455		match self
456		{
457			ReferenceStep::Member { member, offset: _ } => Some(member.clone()),
458			_ => None,
459		}
460	}
461}
462
463#[must_use]
464#[derive(Debug, Clone)]
465pub struct Reference
466{
467	pub base: Poisonable<Identifier>,
468	pub steps: Vec<ReferenceStep>,
469	pub address_depth: u8,
470	pub location: Location,
471	pub location_of_unaddressed: Location,
472}
473
474impl Reference
475{
476	pub fn is_trivial(&self) -> bool
477	{
478		self.steps.is_empty() && self.address_depth == 0
479	}
480}
481
482#[must_use]
483#[derive(Debug, Clone)]
484pub struct Identifier
485{
486	pub name: String,
487	pub location: Location,
488	pub resolution_id: u32,
489	pub is_authoritative: bool,
490}
491
492impl Identifier
493{
494	pub fn inferred(&self) -> Self
495	{
496		Identifier {
497			is_authoritative: false,
498			..self.clone()
499		}
500	}
501
502	pub fn return_value(&self) -> Self
503	{
504		Identifier {
505			name: format!("(return value of '{}')", self.name),
506			is_authoritative: true,
507			..self.clone()
508		}
509	}
510}
511
512impl value_type::Identifier for Identifier {}
513
514impl PartialEq for Identifier
515{
516	fn eq(&self, other: &Identifier) -> bool
517	{
518		if self.resolution_id > 0
519		{
520			self.resolution_id == other.resolution_id
521		}
522		else
523		{
524			self.location == other.location
525		}
526	}
527}