1use std::{collections::{HashMap, HashSet}};
4
5use slotmap::{SlotMap, DefaultKey};
6use anyhow::{Result, anyhow};
7use strum::IntoEnumIterator;
8use strum_macros::{EnumIter};
9
10use crate::parser::{self, CompileTimeConstant, Identifier};
11use crate::parser::ConstantSubstitution;
12
13pub type ParticleID = DefaultKey;
14pub type SimulationID = DefaultKey;
15pub type InteractionID = DefaultKey;
16pub type InteractionQuantityID = DefaultKey;
17pub type FunctionID = DefaultKey;
18
19#[derive(Debug)]
23struct Index<ID: slotmap::Key, T> {
24 elements: SlotMap<ID, T>,
26 name_table: HashMap<String, ID>
28}
29
30impl<ID: slotmap::Key, T> Index<ID,T> {
31 pub fn new() -> Self {
32 Self {
33 elements: SlotMap::with_key(),
34 name_table: HashMap::new()
35 }
36 }
37
38 pub fn insert(&mut self, element: T, name: String) -> Option<T> {
39 let result = match self.name_table.remove(&name) {
41 Some(key) => Some(self.elements.remove(key).unwrap()),
42 None => None
43 };
44 let key = self.elements.insert(element);
46 self.name_table.insert(name, key);
47 result
48 }
49
50 pub fn get(&self, id: &ID) -> Option<&T> {
51 self.elements.get(*id)
52 }
53
54 pub fn get_with_name(&self, name: &str) -> Option<(ID, &T)> {
55 let key = match self.name_table.get(name) {
56 None => return None,
57 Some(key) => key
58 };
59 Some((*key, self.elements.get(*key).unwrap()))
60 }
61
62 pub fn iter(&self) -> impl Iterator<Item=(ID, &T)> {
63 self.elements.iter()
64 }
65
66 pub fn iter_mut(&mut self) -> impl Iterator<Item=(ID, &mut T)> {
67 self.elements.iter_mut()
68 }
69}
70
71pub struct ParticleIndex {
75 index: Index<ParticleID, ParticleIndexEntry>
77}
78
79impl ParticleIndex {
80 pub(crate) fn new(mut parsed_particles: Vec<parser::Particle>) -> Result<Self> {
82 let mut particle_index = Self { index: Index::new() };
84 while !parsed_particles.is_empty() {
86 while let Some(particle) = parsed_particles.pop() {
87 let name = particle.name.clone();
88 match particle_index.index.insert(ParticleIndexEntry::new(particle, &particle_index)?, name) {
90 None => {},
91 Some(entry) => { return Err(
92 anyhow!("Particle {} illegally redefined", entry.get_name())
93 )}
94 }
95 }
96 }
97 Ok(particle_index)
100 }
101
102 pub(crate) fn get(&self, particle_id: ParticleID) -> Option<&ParticleIndexEntry> {
103 self.index.get(&particle_id)
104 }
105
106 pub(crate) fn get_particle_by_name(&self, particle_name: &str) -> Option<(ParticleID, &ParticleIndexEntry)> {
107 self.index.get_with_name(particle_name)
108 }
109
110 pub(crate) fn substitute_constant(&mut self, name: &str, value: &parser::SubstitutionValue) -> Result<()> {
111 for (_, particle_definition) in &mut self.index.iter_mut() {
112 particle_definition.substitute_constant(name, value)?
113 }
114 Ok(())
115 }
116
117}
118
119pub type MemberID = DefaultKey;
120
121#[derive(Debug)]
123pub struct ParticleIndexEntry {
124 particle: parser::Particle,
126 member_index: Index<MemberID, MemberIndexEntry>
128}
129
130impl ParticleIndexEntry {
131 pub(crate) fn new(mut parsed_particle: parser::Particle, _particle_index: &ParticleIndex) -> Result<Self> {
133 let mut member_index = Index::new();
135 for member in parsed_particle.members {
137 let name = member.name.clone();
138 match member_index.insert(MemberIndexEntry::new(member), name) {
140 None => {},
141 Some(entry) => { return Err(
142 anyhow!("Member {} of particle {} illegally redefined",
143 entry.get_name(), parsed_particle.name)
144 )}
145 }
146 }
147 parsed_particle.members = vec![];
149 Ok(ParticleIndexEntry {
150 particle: parsed_particle,
151 member_index
152 })
153 }
154
155 pub(crate) fn substitute_constant(&mut self, name: &str, value: &parser::SubstitutionValue) -> Result<()> {
156 for (_, member_definition) in &mut self.member_index.iter_mut() {
157 member_definition.substitute_constant(name, value)?
158 }
159 Ok(())
160 }
161
162 pub fn get_members(&self) -> impl Iterator<Item = (MemberID, &MemberIndexEntry)> {
163 self.member_index.iter()
164 }
165
166 pub fn get_name(&self) -> &str {
167 &self.particle.name
168 }
169
170 pub fn get_member_by_name<'a>(&'a self, member_name: &str) -> Option<(MemberID, &'a MemberIndexEntry)> {
171 self.member_index.get_with_name(member_name)
172 }
173
174 pub fn get_position_member<'a>(&'a self) -> Option<(MemberID, &'a MemberIndexEntry)> {
176 for (member_id, member) in self.member_index.iter() {
177 if member.is_position() {
178 return Some((member_id, member));
179 }
180 }
181 None
182 }
183
184 pub fn get_member<'a>(&'a self, member_id: &MemberID) -> Option<&'a MemberIndexEntry> {
185 self.member_index.get(member_id)
186 }
187}
188
189#[derive(Debug, Clone)]
191pub struct MemberIndexEntry {
192 member: parser::ParticleMember
193}
194
195impl MemberIndexEntry {
196 pub(crate) fn new(parsed_member: parser::ParticleMember) -> Self {
197 Self {
198 member: parsed_member
199 }
200 }
201
202 pub(crate) fn get_member_size(&self) -> Result<usize> {
203 self.member.typ.get_size()
204 }
205
206 pub(crate) fn substitute_constant(&mut self, name: &str, value: &parser::SubstitutionValue) -> Result<()> {
207 self.member.substitute_constant(name, value)
208 }
209
210 pub(crate) fn is_mutable(&self) -> bool {
211 self.member.mutable
212 }
213
214 pub(crate) fn is_position(&self) -> bool {
215 self.member.is_position
216 }
217
218 pub(crate) fn get_type(&self) -> &parser::FipsType {
219 &self.member.typ
220 }
221
222 pub(crate) fn get_name(&self) -> &str {
223 &self.member.name
224 }
225}
226
227pub struct SimulationIndex {
231 index: Index<SimulationID, SimulationIndexEntry>
232}
233
234impl SimulationIndex {
235 pub(crate) fn new(parsed_simulations: Vec<parser::Simulation>,
237 particle_index: &ParticleIndex)
238 -> Result<Self> {
239 let mut index = Index::new();
241 for simulation in parsed_simulations {
243 let name = simulation.name.clone();
244 match index.insert(SimulationIndexEntry::new(simulation, particle_index)?, name) {
246 None => {},
247 Some(entry) => { return Err(
248 anyhow!("Particle {} illegally redefined", entry.get_name())
249 )}
250 }
251 }
252 Ok(Self { index })
253 }
254
255 pub(crate) fn get_simulation_by_name(&self, name: &str) -> Option<(SimulationID, &SimulationIndexEntry)> {
256 self.index.get_with_name(name)
257 }
258
259 pub(crate) fn get_simulation(&self, simulation_id: &SimulationID) -> Option<&SimulationIndexEntry> {
260 self.index.get(simulation_id)
261 }
262
263 }
274
275pub struct SimulationIndexEntry {
276 simulation: parser::Simulation,
278 default_particle: Option<ParticleID>,
280 blocks: Vec<SimulationBlock>
282}
283
284impl SimulationIndexEntry {
285 pub(crate) fn new(mut simulation: parser::Simulation,
286 particle_index: &ParticleIndex)
287 -> Result<Self> {
288 let default_particle = simulation.default_particle.as_ref()
290 .map(|default_particle_name|
291 particle_index.get_particle_by_name(&default_particle_name)
292 .map(|(particle_id,_)| particle_id)
293 .ok_or(anyhow!("Cannot find default particle {} for simulation {}",
294 default_particle_name, simulation.name))
295 ).transpose()?;
296 let blocks = simulation.blocks;
298 simulation.blocks = vec![];
299 let blocks = blocks.into_iter()
302 .map(|simulation_block| {
303 let (kind, subblocks) = match simulation_block {
305 parser::SimulationBlock::Once(once_block) => (
306 SimulationBlockKind::Once(once_block.step),
307 once_block.subblocks
308 ),
309 parser::SimulationBlock::Step(step_block) => (
310 SimulationBlockKind::Step(step_block.step_range),
311 step_block.subblocks
312 ),
313 };
314 let statement_blocks = subblocks.into_iter().map(|subblock| {
316 let particle_filter = match subblock.particle {
317 None => SimulationParticleFilter::Default,
318 Some(particle_name) => {
319 let (particle_id,_) = particle_index.get_particle_by_name(&particle_name)
321 .ok_or(anyhow!("Cannot find particle {} referenced in simulation {}",
322 particle_name, simulation.name))?;
323 SimulationParticleFilter::Single(particle_id)
324 }
325 };
326 Ok(SimulationStatementBlock {
327 particle_filter,
328 statements: subblock.statements
329 })
330 }).collect::<Result<Vec<_>>>()?;
331 Ok(SimulationBlock {
332 kind, statement_blocks
333 })
334 }).collect::<Result<Vec<_>>>()?;
335 Ok(Self {
337 simulation,
338 default_particle,
339 blocks
340 })
341 }
342
343 pub(crate) fn get_name(&self) -> &str {
344 &self.simulation.name
345 }
346
347 pub(crate) fn get_default_particle(&self) -> Option<ParticleID> {
348 self.default_particle
349 }
350
351 pub(crate) fn get_blocks(&self) -> &[SimulationBlock] {
356 &self.blocks
357 }
358}
359
360pub enum SimulationBlockKind {
362 Once(parser::CompileTimeConstant<usize>),
364 Step(parser::StepRange)
366}
367
368pub struct SimulationBlock {
371 pub kind: SimulationBlockKind,
373 pub statement_blocks: Vec<SimulationStatementBlock>
375}
376
377pub enum SimulationParticleFilter {
379 Default,
381 Single(ParticleID)
383}
384
385pub struct SimulationStatementBlock {
386 pub particle_filter: SimulationParticleFilter,
388 pub statements: Vec<parser::Statement>
390}
391
392pub struct InteractionIndex {
395 index: Index<InteractionID, InteractionIndexEntry>
396}
397
398impl InteractionIndex {
399 pub(crate) fn new(parsed_interactions: Vec<parser::Interaction>,
400 particle_index: &ParticleIndex) -> Result<Self>
401 {
402 let mut index = Index::new();
404 for interaction in parsed_interactions {
406 let name = interaction.name.clone();
407 match index.insert(InteractionIndexEntry::new(interaction, particle_index)?, name) {
409 None => {},
410 Some(entry) => { return Err(
411 anyhow!("Interaction {} illegally redefined", entry.get_name())
412 )}
413 }
414 }
415 Ok(Self { index })
416 }
417
418 pub(crate) fn get_interaction_by_name(&self, interaction_name: &str) -> Option<(InteractionID, &InteractionIndexEntry)> {
419 self.index.get_with_name(interaction_name)
420 }
421
422 pub(crate) fn get(&self, interaction_id: InteractionID) -> Option<&InteractionIndexEntry> {
423 self.index.get(&interaction_id)
424 }
425
426 pub(crate) fn iter(&self) -> impl Iterator<Item=(InteractionID, &InteractionIndexEntry)> {
427 self.index.iter()
428 }
429
430 pub(crate) fn substitute_constant(&mut self, name: &str, value: &parser::SubstitutionValue) -> Result<()> {
431 for (_, interaction_definition) in &mut self.index.iter_mut() {
432 interaction_definition.substitute_constant(name, value)?
433 }
434 Ok(())
435 }
436}
437
438pub struct InteractionIndexEntry {
439 interaction: parser::Interaction,
441 particle_id_a: ParticleID,
443 particle_id_b: ParticleID,
445 quantity_index: Index<InteractionQuantityID, InteractionQuantityIndexEntry>
447}
448
449impl InteractionIndexEntry {
450 pub(crate) fn new(mut interaction: parser::Interaction, particle_index: &ParticleIndex) -> Result<Self> {
451 let mut quantity_index = Index::new();
453 for quantity in interaction.quantities {
455 let name = quantity.name.clone();
456 match quantity_index.insert(InteractionQuantityIndexEntry::new(quantity), name) {
458 None => {},
459 Some(entry) => { return Err(
460 anyhow!("Quantitiy {} of interaction {} illegally redefined",
461 entry.get_name(), interaction.name)
462 )}
463 }
464 }
465 interaction.quantities = vec![];
467 let particle_id_a = particle_index.get_particle_by_name(&interaction.type_a)
469 .ok_or(anyhow!("Cannot resolve particle type {} in interaction {}",
470 &interaction.type_a, interaction.name))?.0;
471 let particle_id_b = particle_index.get_particle_by_name(&interaction.type_b)
472 .ok_or(anyhow!("Cannot resolve particle type {} in interaction {}",
473 &interaction.type_a, interaction.name))?.0;
474 Ok(Self {
476 interaction,
477 quantity_index,
478 particle_id_a, particle_id_b
479 })
480 }
481
482 pub(crate) fn get_name(&self) -> &str {
484 &self.interaction.name
485 }
486
487 pub(crate) fn get_type_a(&self) -> &str {
488 &self.interaction.type_a
489 }
490
491 pub(crate) fn get_type_b(&self) -> &str {
492 &self.interaction.type_b
493 }
494
495 pub(crate) fn get_name_a(&self) -> &Identifier {
496 &self.interaction.name_a
497 }
498
499 pub(crate) fn get_name_b(&self) -> &Identifier {
500 &self.interaction.name_b
501 }
502
503 pub(crate) fn get_distance_vec(&self) -> Option<&String> {
504 self.interaction.distance_vec.as_ref()
505 }
506
507 pub(crate) fn get_quantity(&self, quantity_id: InteractionQuantityID) -> Option<&InteractionQuantityIndexEntry> {
508 self.quantity_index.get(&quantity_id)
509 }
510
511 pub(crate) fn get_cutoff(&self) -> CompileTimeConstant<f64> {
512 self.interaction.cutoff.clone()
513 }
514
515 pub(crate) fn get_distance_identifier(&self) -> &Identifier {
516 &self.interaction.distance
517 }
518
519 pub(crate) fn get_common_block(&self) -> Option<&Vec<parser::Statement>> {
520 self.interaction.common_block.as_ref()
521 }
522
523 pub(crate) fn get_quantity_by_name(&self, quantity: &str) -> Option<(InteractionQuantityID, &InteractionQuantityIndexEntry)> {
525 self.quantity_index.get_with_name(quantity)
526 }
527
528 pub(crate) fn iter(&self) -> impl Iterator<Item = (InteractionQuantityID, &InteractionQuantityIndexEntry)> {
529 self.quantity_index.iter()
530 }
531
532 pub(crate) fn get_affected_particles(&self, _particle_index: &ParticleIndex) -> Result<HashSet<ParticleID>> {
534 let mut affected_particles = HashSet::new();
535 affected_particles.insert(self.particle_id_a);
537 affected_particles.insert(self.particle_id_b);
538 Ok(affected_particles)
540 }
541
542 pub(crate) fn substitute_constant(&mut self, name: &str, value: &parser::SubstitutionValue) -> Result<()> {
543 self.interaction.cutoff.substitute_constant(name, value)
544 }
545}
546
547pub struct InteractionQuantityIndexEntry {
548 quantity: parser::InteractionQuantity
549}
550
551impl InteractionQuantityIndexEntry {
552 pub(crate) fn new(quantity: parser::InteractionQuantity) -> Self {
554 Self {
555 quantity
556 }
557 }
558
559 pub(crate) fn get_name(&self) -> &str {
560 &self.quantity.name
561 }
562
563 pub(crate) fn get_target_a(&self) -> &str {
564 &self.quantity.target_a
565 }
566
567 pub(crate) fn get_target_b(&self) -> &str {
568 &self.quantity.target_b
569 }
570
571 pub(crate) fn get_expression(&self) -> &parser::Expression {
572 &self.quantity.expression
573 }
574
575 pub(crate) fn get_reduction_method(&self) -> &parser::ReductionMethod {
576 &self.quantity.reduction_method
577 }
578
579 pub(crate) fn get_symmetry(&self) -> parser::InteractionSymmetry {
580 self.quantity.symmetry
581 }
582}
583
584
585pub(crate) struct FunctionIndex {
589 index: Index<FunctionID, FunctionIndexEntry>
590}
591
592impl FunctionIndex {
593 pub(crate) fn new(externs: Vec<parser::ExternFunctionDecl>) -> Result<Self> {
595 let mut index = Index::new();
596 for builtin in BuiltinFunction::get_all() {
597 let name = builtin.get_name().to_string();
598 match index.insert(FunctionIndexEntry::Builtin(builtin), name) {
599 Some(entry) => { return Err(anyhow!("Internal: builtin name {} duplicated", entry.get_name())) },
600 None => {},
601 }
602 }
603 for externfunc in externs {
604 let name = externfunc.name.clone();
605 match index.insert(FunctionIndexEntry::Extern(externfunc), name) {
606 Some(entry) => { return Err(anyhow!("Cannot redefine function {}", entry.get_name())) },
607 None => {},
608 }
609 }
610
611 Ok(Self {
612 index
613 })
614 }
615
616 pub(crate) fn get(&self, function_id: FunctionID) -> Option<&FunctionIndexEntry> {
617 self.index.get(&function_id)
618 }
619
620 pub(crate) fn get_functions(&self) -> impl Iterator<Item = (FunctionID, &FunctionIndexEntry)> {
621 self.index.iter()
622 }
623
624 pub(crate) fn substitute_constant(&mut self, name: &str, value: &parser::SubstitutionValue) -> Result<()> {
625 for (_, function_def) in &mut self.index.iter_mut() {
626 function_def.substitute_constant(name, value)?
627 }
628 Ok(())
629 }
630}
631
632pub(crate) enum FunctionIndexEntry {
633 Extern(parser::ExternFunctionDecl),
634 Builtin(BuiltinFunction)
635}
636
637impl FunctionIndexEntry {
638 pub(crate) fn get_name(&self) -> &str {
639 match self {
640 FunctionIndexEntry::Extern(externfunc) => { &externfunc.name },
641 FunctionIndexEntry::Builtin(builtin) => { builtin.get_name() },
642 }
643 }
644
645 pub(crate) fn needs_callback_target_ptr(&self) -> bool {
646 match self {
647 FunctionIndexEntry::Extern(_) => { false }, FunctionIndexEntry::Builtin(builtin) => { builtin.needs_callback_target_ptr() },
649 }
650 }
651
652 pub(crate) fn returns_array(&self) -> bool {
653 match self {
654 FunctionIndexEntry::Extern(externfunc) => {
655 match externfunc.return_type {
656 parser::FipsType::Double | parser::FipsType::Int64 => false,
657 parser::FipsType::Array { .. } => true,
658 }
659 },
660 FunctionIndexEntry::Builtin(builtin) => { builtin.returns_array() },
661 }
662 }
663
664 pub(crate) fn substitute_constant(&mut self, name: &str, value: &parser::SubstitutionValue) -> Result<()> {
665 match self {
666 FunctionIndexEntry::Extern(func_decl) => { func_decl.substitute_constant(name, value) },
667 FunctionIndexEntry::Builtin(_) => Ok(()),
668 }
669 }
670}
671
672#[derive(EnumIter)]
673pub(crate) enum BuiltinFunction {
674 Sqrt,
675 Sin,
676 Cos,
677 RandomNormal
678}
679
680impl BuiltinFunction {
681 pub(crate) fn get_all() -> Vec<Self> {
683 Self::iter().collect::<Vec<_>>()
684 }
685
686 pub(crate) fn get_name(&self) -> &'static str {
688 match self {
689 Self::Sqrt => "sqrt",
690 Self::Sin => "sin",
691 Self::Cos => "cos",
692 Self::RandomNormal => "random_normal",
693 }
694 }
695
696 pub(crate) fn needs_callback_target_ptr(&self) -> bool {
699 match self {
700 BuiltinFunction::Sqrt => false,
701 BuiltinFunction::Sin => false,
702 BuiltinFunction::Cos => false,
703 BuiltinFunction::RandomNormal => true,
704 }
705 }
706
707 pub(crate) fn returns_array(&self) -> bool {
708 match self {
709 Self::Sqrt => false,
710 Self::Sin => false,
711 Self::Cos => false,
712 Self::RandomNormal => false,
713 }
714 }
715}
716
717
718