Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions build/Project.csproj.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
<Project>
<PropertyGroup>
<Nullable>annotations</Nullable>
</PropertyGroup>
</Project>
17 changes: 10 additions & 7 deletions src/Firmware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public class PortPinInfo
/// Specifies the microcontroller port where the pin is located.
/// </summary>
[YamlMember(Order = -1)]
public string Port;
public string Port = "";

/// <summary>
/// Specifies the unique pin number in the defined port.
Expand Down Expand Up @@ -357,12 +357,9 @@ class PortPinInfoTypeConverter(IDeserializer deserializer) : IYamlTypeConverter

public IDeserializer Deserializer { get; } = deserializer ?? throw new ArgumentNullException(nameof(deserializer));

public bool Accepts(Type type)
{
return type == typeof(PortPinInfo);
}
public bool Accepts(Type type) => type == typeof(PortPinInfo);

public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
var portPin = Deserializer.Deserialize<Dictionary<object, object>>(parser);
if (portPin.TryGetValue(DirectionProperty, out object value))
Expand All @@ -381,7 +378,7 @@ public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeseria
throw new YamlException($"Required property '{DirectionProperty}' not found when deserializing type '{typeof(PortPinInfo)}'.");
}

public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
throw new NotImplementedException();
}
Expand All @@ -397,6 +394,9 @@ class LowerCaseEnumTypeConverter : IYamlTypeConverter

public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
if (value is null)
return;

var scalarStyle = ScalarStyle.Any;
var scalarValue = LowerCaseNamingConvention.Instance.Apply(value.ToString());
if (scalarValue == "off")
Expand All @@ -415,6 +415,9 @@ class CamelCaseEnumTypeConverter : IYamlTypeConverter

public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
if (value is null)
return;

emitter.Emit(new Scalar(CamelCaseNamingConvention.Instance.Apply(value.ToString())));
}
}
Expand Down
84 changes: 45 additions & 39 deletions src/Interface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class DeviceInfo
/// <summary>
/// Specifies the name of the device.
/// </summary>
public string Device;
public string Device = "";

/// <summary>
/// Specifies the unique identifier for this device type.
Expand All @@ -28,12 +28,12 @@ public class DeviceInfo
/// <summary>
/// Specifies the version of the device firmware.
/// </summary>
public HarpVersion FirmwareVersion;
public HarpVersion? FirmwareVersion;

/// <summary>
/// Specifies the version of the device hardware.
/// </summary>
public HarpVersion HardwareTargets;
public HarpVersion? HardwareTargets;

/// <summary>
/// Specifies the collection of registers implementing the device function.
Expand Down Expand Up @@ -151,7 +151,7 @@ public class RegisterInfo
/// <summary>
/// Specifies the name of the bit mask or group mask used to represent the payload value.
/// </summary>
public string MaskType;
public string MaskType = "";

/// <summary>
/// Specifies the minimum allowable value for the payload.
Expand All @@ -171,7 +171,7 @@ public class RegisterInfo
/// <summary>
/// Specifies the name of the type used to represent the payload value in the high-level interface.
/// </summary>
public string InterfaceType;
public string InterfaceType = "";

/// <summary>
/// Specifies a custom converter which will be used to parse or format the payload value.
Expand All @@ -187,7 +187,7 @@ public class RegisterInfo
/// Specifies a collection of payload members describing the contents
/// of the raw payload value.
/// </summary>
public Dictionary<string, PayloadMemberInfo> PayloadSpec;
public Dictionary<string, PayloadMemberInfo>? PayloadSpec;

/// <summary>
/// Gets a value indicating whether a custom converter will be used to parse or
Expand Down Expand Up @@ -229,7 +229,7 @@ public class PayloadMemberInfo
/// <summary>
/// Specifies the name of the bit mask or group mask used to represent this payload member.
/// </summary>
public string MaskType;
public string MaskType = "";

/// <summary>
/// Specifies the minimum allowable value for this payload member.
Expand All @@ -249,7 +249,7 @@ public class PayloadMemberInfo
/// <summary>
/// Specifies the name of the type used to represent this payload member in the high-level interface.
/// </summary>
public string InterfaceType;
public string InterfaceType = "";

/// <summary>
/// Specifies a custom converter which will be used to parse or format this payload member.
Expand Down Expand Up @@ -350,7 +350,7 @@ public class MaskValue
/// <summary>
/// Specifies a summary description of the mask value function.
/// </summary>
public string Description;
public string Description = "";
}

internal static partial class TemplateHelper
Expand Down Expand Up @@ -478,15 +478,20 @@ public static string GetParseConversion(RegisterInfo register, string expression
else if (register.InterfaceType == "string")
return $"PayloadMarshal.ReadUtf8String({expression})";
else
return GetConversionToInterfaceType(register.InterfaceType ?? register.MaskType, expression);
return GetConversionToInterfaceType(
string.IsNullOrEmpty(register.InterfaceType) ? register.MaskType : register.InterfaceType,
expression);
}

public static string GetFormatConversion(RegisterInfo register, string expression)
{
if (register.PayloadSpec != null || register.InterfaceType == "string" || register.HasConverter)
return $"FormatPayload({expression})";
else
return GetConversionFromInterfaceType(register.InterfaceType ?? register.MaskType, register.PayloadInterfaceType, expression);
return GetConversionFromInterfaceType(
string.IsNullOrEmpty(register.InterfaceType) ? register.MaskType : register.InterfaceType,
register.PayloadInterfaceType,
expression);
}

public static string GetConversionToInterfaceType(string interfaceType, string expression)
Expand Down Expand Up @@ -608,7 +613,9 @@ public static string GetPayloadMemberParser(
{
return $"ParsePayload{name}({expression})";
}
return GetConversionToInterfaceType(member.InterfaceType ?? member.MaskType, expression);
return GetConversionToInterfaceType(
string.IsNullOrEmpty(member.InterfaceType) ? member.MaskType : member.InterfaceType,
expression);
}

public static string GetPayloadMemberAssignmentFormatter(
Expand Down Expand Up @@ -661,7 +668,8 @@ public static string GetPayloadMemberValueFormatter(

var isBoolean = member.InterfaceType == "bool" && !member.HasConverter;
var payloadInterfaceType = GetInterfaceType(payloadType);
if (!string.IsNullOrEmpty(member.InterfaceType ?? member.MaskType))
var memberInterfaceType = string.IsNullOrEmpty(member.InterfaceType) ? member.MaskType : member.InterfaceType;
if (!string.IsNullOrEmpty(memberInterfaceType))
{
if (isBoolean)
{
Expand Down Expand Up @@ -697,23 +705,23 @@ class HarpVersionTypeConverter : IYamlTypeConverter
{
public static readonly HarpVersionTypeConverter Instance = new();

public bool Accepts(Type type)
{
return type == typeof(HarpVersion);
}
public bool Accepts(Type type) => type == typeof(HarpVersion);

public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
var scalar = parser.Consume<Scalar>();
return HarpVersion.Parse(scalar.Value);
}

public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
if (value is not HarpVersion version)
return;

var scalar = new Scalar(
AnchorName.Empty,
TagName.Empty,
((HarpVersion)value).ToString(),
version.ToString(),
ScalarStyle.DoubleQuoted,
isPlainImplicit: false,
isQuotedImplicit: true);
Expand All @@ -727,12 +735,12 @@ class HexValueTypeConverter : IYamlTypeConverter

public bool Accepts(Type type) => false;

public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
return rootDeserializer(type);
}

public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
emitter.Emit(new Scalar(string.Format($"0x{value:X}")));
}
Expand All @@ -750,17 +758,14 @@ class MaskValueTypeConverter : IYamlTypeConverter
.WithTypeConverter(HexValueTypeConverter.Instance)
.BuildValueSerializer();

public bool Accepts(Type type)
{
return type == typeof(MaskValue);
}
public bool Accepts(Type type) => type == typeof(MaskValue);

public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
if (parser.TryConsume(out MappingStart _))
if (parser.TryConsume<MappingStart>(out var _))
{
var maskValue = new MaskValue();
while (!parser.TryConsume(out MappingEnd _))
while (!parser.TryConsume<MappingEnd>(out var _))
{
var key = parser.Consume<Scalar>();
var value = parser.Consume<Scalar>();
Expand All @@ -786,9 +791,11 @@ public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeseria
}
}

public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
var maskValue = (MaskValue)value;
if (value is not MaskValue maskValue)
return;

if (string.IsNullOrEmpty(maskValue.Description))
HexValueTypeConverter.Instance.WriteYaml(emitter, maskValue.Value, typeof(int), serializer);
else
Expand All @@ -800,17 +807,14 @@ class RegisterAccessTypeConverter : IYamlTypeConverter
{
public static readonly RegisterAccessTypeConverter Instance = new();

public bool Accepts(Type type)
{
return type == typeof(RegisterAccess);
}
public bool Accepts(Type type) => type == typeof(RegisterAccess);

public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
public object? ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
{
if (parser.TryConsume(out SequenceStart _))
if (parser.TryConsume<SequenceStart>(out var _))
{
RegisterAccess value = 0;
while (parser.TryConsume(out Scalar scalar))
while (parser.TryConsume<Scalar>(out var scalar))
{
value |= (RegisterAccess)Enum.Parse(typeof(RegisterAccess), scalar.Value);
}
Expand All @@ -824,9 +828,11 @@ public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeseria
}
}

public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
public void WriteYaml(IEmitter emitter, object? value, Type type, ObjectSerializer serializer)
{
var access = (RegisterAccess)value;
if (value is not RegisterAccess access)
return;

switch (access)
{
case RegisterAccess.Read:
Expand Down
8 changes: 4 additions & 4 deletions src/TemplateBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ namespace Harp.Generators;

internal abstract class TemplateBase
{
private StringBuilder builder;
private CompilerErrorCollection errors;
private StringBuilder? builder;
private CompilerErrorCollection? errors;
private string currentIndent = string.Empty;
private Stack<int> indents;
private Stack<int>? indents;

public virtual IDictionary<string, object> Session { get; set; }
public virtual IDictionary<string, object>? Session { get; set; }

public string FileName { get; set; } = string.Empty;

Expand Down
21 changes: 12 additions & 9 deletions tests/FirmwareGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Harp.Generators.Tests;
[TestClass]
public sealed class FirmwareGeneratorTests
{
DirectoryInfo outputDirectory;
DirectoryInfo? outputDirectory;

[TestInitialize]
public void Initialize()
Expand Down Expand Up @@ -49,14 +49,17 @@ public void FirmwareTemplate_GenerateAndBuild(string metadataFileName, params st
}
catch (AssertFailedException)
{
outputDirectory.Create();
File.WriteAllText(Path.Combine(outputDirectory.FullName, appOutputFileName), headers.App);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appImplOutputFileName), implementation.App);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appFuncsOutputFileName), headers.AppFuncs);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appFuncsImplOutputFileName), implementation.AppFuncs);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appRegsOutputFileName), headers.AppRegs);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appRegsImplOutputFileName), implementation.AppRegs);
File.WriteAllText(Path.Combine(outputDirectory.FullName, interruptsOutputFileName), implementation.Interrupts);
if (outputDirectory is not null)
{
outputDirectory.Create();
File.WriteAllText(Path.Combine(outputDirectory.FullName, appOutputFileName), headers.App);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appImplOutputFileName), implementation.App);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appFuncsOutputFileName), headers.AppFuncs);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appFuncsImplOutputFileName), implementation.AppFuncs);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appRegsOutputFileName), headers.AppRegs);
File.WriteAllText(Path.Combine(outputDirectory.FullName, appRegsImplOutputFileName), implementation.AppRegs);
File.WriteAllText(Path.Combine(outputDirectory.FullName, interruptsOutputFileName), implementation.Interrupts);
}
throw;
}
}
Expand Down
16 changes: 9 additions & 7 deletions tests/InterfaceGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ namespace Harp.Generators.Tests;
[TestClass]
public sealed class InterfaceGeneratorTests
{
DirectoryInfo outputDirectory;
string payloadExtensions;
DirectoryInfo? outputDirectory;
string payloadExtensions = "";

[TestInitialize]
public void Initialize()
Expand All @@ -24,24 +24,26 @@ public void DeviceTemplate_GenerateAndBuildWithoutErrors(string metadataFileName
{
metadataFileName = TestHelper.GetMetadataPath(metadataFileName);
var deviceMetadata = TestHelper.ReadDeviceMetadata(metadataFileName);
var generator = new InterfaceGenerator(deviceMetadata, typeof(InterfaceGeneratorTests).Namespace);
var generator = new InterfaceGenerator(deviceMetadata, typeof(InterfaceGeneratorTests).Namespace ?? "");
var implementation = generator.GenerateImplementation();
var outputFileName = Path.GetFileNameWithoutExtension(metadataFileName);
var deviceOutputFileName = $"{outputFileName}.cs";
var asyncDeviceOutputFileName = $"{outputFileName}.async.cs";
var customImplementation = TestHelper.GetManifestResourceText($"EmbeddedSources.{outputFileName}.cs");
try
{
TestHelper.AssertNoGeneratorErrors(generator.Errors);
CompilerTestHelper.CompileFromSource(implementation.Device, implementation.AsyncDevice, payloadExtensions, customImplementation);
TestHelper.AssertExpectedOutput(implementation.Device, deviceOutputFileName);
TestHelper.AssertExpectedOutput(implementation.AsyncDevice, asyncDeviceOutputFileName);
}
catch (AssertFailedException)
{
outputDirectory.Create();
File.WriteAllText(Path.Combine(outputDirectory.FullName, deviceOutputFileName), implementation.Device);
File.WriteAllText(Path.Combine(outputDirectory.FullName, asyncDeviceOutputFileName), implementation.AsyncDevice);
if (outputDirectory is not null)
{
outputDirectory.Create();
File.WriteAllText(Path.Combine(outputDirectory.FullName, deviceOutputFileName), implementation.Device);
File.WriteAllText(Path.Combine(outputDirectory.FullName, asyncDeviceOutputFileName), implementation.AsyncDevice);
}
throw;
}
}
Expand Down
Loading
Loading