1use 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 ArrayByView,
409 ArrayByPointer,
410 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}