1 //
2 // Copyright (c) 2010-2018 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Linq;
9 using System.Collections.Generic;
10 using Antmicro.Migrant;
11 using Sprache;
12 using System.Reflection;
13 
14 namespace Antmicro.Renode.PlatformDescription.Syntax
15 {
16     public class Entry : IPositionAware<Entry>, IWithPosition, IPrefixable, IInitable
17     {
Entry(string variableName, StringWithPosition type, IEnumerable<RegistrationInfo> registrationInfo, IEnumerable<Attribute> attributes, bool isLocal, StringWithPosition alias)18         public Entry(string variableName, StringWithPosition type, IEnumerable<RegistrationInfo> registrationInfo, IEnumerable<Attribute> attributes, bool isLocal, StringWithPosition alias)
19         {
20             VariableName = variableName;
21             baseVariableName = variableName;
22             Type = type;
23             RegistrationInfos = registrationInfo;
24             Attributes = attributes;
25             IsLocal = isLocal;
26             Alias = alias;
27 
28         }
29 
SetPos(Position startPos, int length)30         public Entry SetPos(Position startPos, int length)
31         {
32             var copy = SerializationProvider.Instance.DeepClone(this);
33             copy.StartPosition = startPos;
34             copy.Length = length;
35             return copy;
36         }
37 
Prefix(string with)38         public void Prefix(string with)
39         {
40             VariableName = with + baseVariableName;
41         }
42 
MergeWith(Entry entry)43         public Entry MergeWith(Entry entry)
44         {
45             if(Type != null && entry.Type != null && Type.Value != entry.Type.Value)
46             {
47                 throw new InvalidOperationException($"Internal error during entry merge: merging entries of different types: {entry.Type?.Value} and {Type?.Value}.");
48             }
49             if(entry.VariableName != VariableName || entry.Variable != null || Variable != null)
50             {
51                 throw new InvalidOperationException($"Internal error during entry merge: merging entries for different variables: {entry.VariableName} and {VariableName}.");
52             }
53             if(entry.Type != null)
54             {
55                 Type = entry.Type;
56             }
57             if(entry.RegistrationInfos != null)
58             {
59                 RegistrationInfos = entry.RegistrationInfos;
60                 Alias = entry.Alias;
61             }
62             if(entry.Attributes == null || Attributes == null)
63             {
64                 Attributes = Attributes ?? entry.Attributes;
65             }
66             else
67             {
68                 var mergedAttributes = new List<Attribute>();
69                 // add all ctor and property attributes we don't have in the second entry
70                 mergedAttributes.AddRange(Attributes.OfType<ConstructorOrPropertyAttribute>()
71                                           .Where(x => !entry.Attributes.OfType<ConstructorOrPropertyAttribute>().Any(y => y.Name == x.Name)));
72                 // then all attributes from second entry
73                 mergedAttributes.AddRange(entry.Attributes.OfType<ConstructorOrPropertyAttribute>());
74 
75                 // since interrupts are already flattened, we can merge them the same way as property attributes
76                 mergedAttributes.AddRange(Attributes.OfType<IrqAttribute>()
77                                           .Where(x => !entry.Attributes.OfType<IrqAttribute>()
78                                                  .Any(y => x.Sources.Single().Ends.Single() == y.Sources.Single().Ends.Single())));
79                 mergedAttributes.AddRange(entry.Attributes.OfType<IrqAttribute>());
80 
81                 var ourInit = Attributes.OfType<InitAttribute>().SingleOrDefault();
82                 var theirInit = entry.Attributes.OfType<InitAttribute>().SingleOrDefault();
83                 if(ourInit == null ^ theirInit == null)
84                 {
85                     mergedAttributes.Add(ourInit ?? theirInit);
86                 }
87                 else if(ourInit != null)
88                 {
89                     mergedAttributes.Add(ourInit.Merge(theirInit));
90                 }
91 
92                 Attributes = mergedAttributes;
93             }
94             return this;
95         }
96 
FlattenIrqAttributes()97         public void FlattenIrqAttributes()
98         {
99             // one must (and should) flatten attributes after premerge validation and before merge
100             var multiplexedAttributes = Attributes.OfType<IrqAttribute>();
101             var result = new List<IrqAttribute>();
102             Func<SingleOrMultiIrqEnd, IEnumerable<SingleOrMultiIrqEnd>> selector = x => x.Ends.Select(y => x.WithEnds(new[] { y }));
103             foreach(var multiplexedAttribute in multiplexedAttributes)
104             {
105                 var sourcesAsArray = multiplexedAttribute.Sources.SelectMany(selector).ToArray();
106                 foreach(var attribute in multiplexedAttribute.Destinations)
107                 {
108                     // Irq -> none
109                     if(attribute.DestinationPeripheral == null)
110                     {
111                         result.Add(multiplexedAttribute);
112                         continue;
113                     }
114                     var destinationsAsArray = attribute.Destinations.SelectMany(selector).ToArray();
115                     for(var i = 0; i < sourcesAsArray.Length; i++)
116                     {
117                         result.Add(multiplexedAttribute.SingleAttributeWithInheritedPosition(sourcesAsArray[i], attribute.DestinationPeripheral, destinationsAsArray[i]));
118                     }
119                 }
120             }
121             Attributes = Attributes.Except(multiplexedAttributes).Concat(result).ToArray();
122         }
123 
MakeShallowCopy()124         public Entry MakeShallowCopy()
125         {
126             return new Entry(VariableName, Type, RegistrationInfos, Attributes, IsLocal, Alias);
127         }
128 
129         public string VariableName { get; private set; }
130         public StringWithPosition Type { get; private set; }
131         public IEnumerable<RegistrationInfo> RegistrationInfos { get; private set; }
132         public IEnumerable<Attribute> Attributes { get; private set; }
133         public bool IsLocal { get; private set; }
134         public Position StartPosition { get; private set; }
135         public int Length { get; private set; }
136         public StringWithPosition Alias { get; private set; }
137         public ConstructorInfo Constructor { get; set; }
138         public Variable Variable { get; set; }
139 
140         private readonly string baseVariableName;
141     }
142 }
143