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