blob: c3fa1ae1d5ed0c1fc92e84f0be63dd09b1f5be31 [file] [log] [blame]
//
// Copyright (c) 2010-2018 Antmicro
//
// This file is licensed under the MIT License.
// Full license text is available in 'licenses/MIT.txt'.
//
using System;
using System.Linq;
using System.Collections.Generic;
using Antmicro.Migrant;
using Sprache;
using System.Reflection;
namespace Antmicro.Renode.PlatformDescription.Syntax
{
public class Entry : IPositionAware<Entry>, IWithPosition, IPrefixable, IInitable
{
public Entry(string variableName, StringWithPosition type, IEnumerable<RegistrationInfo> registrationInfo, IEnumerable<Attribute> attributes, bool isLocal, StringWithPosition alias)
{
VariableName = variableName;
Type = type;
RegistrationInfos = registrationInfo;
Attributes = attributes;
IsLocal = isLocal;
Alias = alias;
}
public Entry SetPos(Position startPos, int length)
{
var copy = SerializationProvider.Instance.DeepClone(this);
copy.StartPosition = startPos;
copy.Length = length;
return copy;
}
public void Prefix(string with)
{
VariableName = with + VariableName;
}
public Entry MergeWith(Entry entry)
{
if(entry.VariableName != VariableName || entry.Type != null || entry.Variable != null || Variable != null)
{
throw new InvalidOperationException("Internal error during entry merge.");
}
if(entry.RegistrationInfos != null)
{
RegistrationInfos = entry.RegistrationInfos;
Alias = entry.Alias;
}
if(entry.Attributes == null || Attributes == null)
{
Attributes = Attributes ?? entry.Attributes;
}
else
{
var mergedAttributes = new List<Attribute>();
// add all ctor and property attributes we don't have in the second entry
mergedAttributes.AddRange(Attributes.OfType<ConstructorOrPropertyAttribute>()
.Where(x => !entry.Attributes.OfType<ConstructorOrPropertyAttribute>().Any(y => y.Name == x.Name)));
// then all attributes from second entry
mergedAttributes.AddRange(entry.Attributes.OfType<ConstructorOrPropertyAttribute>());
// since interrupts are already flattened, we can merge them the same way as property attributes
mergedAttributes.AddRange(Attributes.OfType<IrqAttribute>()
.Where(x => !entry.Attributes.OfType<IrqAttribute>()
.Any(y => x.Sources.Single().Ends.Single() == y.Sources.Single().Ends.Single())));
mergedAttributes.AddRange(entry.Attributes.OfType<IrqAttribute>());
var ourInit = Attributes.OfType<InitAttribute>().SingleOrDefault();
var theirInit = entry.Attributes.OfType<InitAttribute>().SingleOrDefault();
if(ourInit == null ^ theirInit == null)
{
mergedAttributes.Add(ourInit ?? theirInit);
}
else if(ourInit != null)
{
mergedAttributes.Add(ourInit.Merge(theirInit));
}
Attributes = mergedAttributes;
}
return this;
}
public void FlattenIrqAttributes()
{
// one must (and should) flatten attributes after premerge validation and before merge
var multiplexedAttributes = Attributes.OfType<IrqAttribute>();
var result = new List<IrqAttribute>();
Func<SingleOrMultiIrqEnd, IEnumerable<SingleOrMultiIrqEnd>> selector = x => x.Ends.Select(y => x.WithEnds(new[] { y }));
foreach(var multiplexedAttribute in multiplexedAttributes)
{
var sourcesAsArray = multiplexedAttribute.Sources.SelectMany(selector).ToArray();
foreach(var attribute in multiplexedAttribute.Destinations)
{
// Irq -> none
if(attribute.DestinationPeripheral == null)
{
result.Add(multiplexedAttribute);
continue;
}
var destinationsAsArray = attribute.Destinations.SelectMany(selector).ToArray();
for(var i = 0; i < sourcesAsArray.Length; i++)
{
result.Add(multiplexedAttribute.SingleAttributeWithInheritedPosition(sourcesAsArray[i], attribute.DestinationPeripheral, destinationsAsArray[i]));
}
}
}
Attributes = Attributes.Except(multiplexedAttributes).Concat(result).ToArray();
}
public Entry MakeShallowCopy()
{
return new Entry(VariableName, Type, RegistrationInfos, Attributes, IsLocal, Alias);
}
public string VariableName { get; private set; }
public StringWithPosition Type { get; private set; }
public IEnumerable<RegistrationInfo> RegistrationInfos { get; private set; }
public IEnumerable<Attribute> Attributes { get; private set; }
public bool IsLocal { get; private set; }
public Position StartPosition { get; private set; }
public int Length { get; private set; }
public StringWithPosition Alias { get; private set; }
public ConstructorInfo Constructor { get; set; }
public Variable Variable { get; set; }
}
}