Skip to content

Commit

Permalink
Merge pull request #3 from rbergen/netcsharp-updates
Browse files Browse the repository at this point in the history
Bump Lib and Assember to .NET 8, apply heaps of C# 12 improvements
  • Loading branch information
rbergen authored Aug 23, 2024
2 parents 4c76576 + 3010991 commit 9e171ad
Show file tree
Hide file tree
Showing 91 changed files with 444 additions and 780 deletions.
8 changes: 3 additions & 5 deletions src/MixAssembler/Assembler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using MixAssembler.Finding;
Expand Down Expand Up @@ -71,12 +71,10 @@ public static InstructionInstanceBase[] Assemble(string[] sourceLines, out PreIn
if (status.Findings.ContainsErrors)
return null;

symbols = new SymbolCollection();
foreach (SymbolBase symbol in status.Symbols.Where(symbol => symbol is ValueSymbol))
symbols.Add(symbol);
symbols = [.. status.Symbols.Where(symbol => symbol is ValueSymbol)];

status.Findings.Add(new AssemblyInfo("assembly completed successfully", int.MinValue, LineSection.EntireLine, 0, 0));
return list.ToArray();
return [.. list];
}

public static InstructionInstanceBase Assemble(string instructionLine, int locationCounter, out ParsedSourceLine parsedLine, SymbolCollection symbols, out AssemblyFindingCollection findings)
Expand Down
2 changes: 1 addition & 1 deletion src/MixAssembler/AssemblingStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace MixAssembler
{
public class AssemblingStatus
{
public AssemblyFindingCollection Findings { get; } = new();
public AssemblyFindingCollection Findings { get; } = [];

public void ReportError(LineSection lineSection, int causeStartIndex, int causeLength, ValidationError error)
=> Findings.Add(new AssemblyError(LineNumber, lineSection, causeStartIndex, causeLength, error));
Expand Down
9 changes: 4 additions & 5 deletions src/MixAssembler/Finding/AssemblyError.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using MixLib.Misc;
using MixLib.Misc;

namespace MixAssembler.Finding
{
public class AssemblyError : ValidationFinding
public class AssemblyError(int lineNumber, LineSection lineSection, int causeStartIndex, int causeLength, ValidationError error)
: ValidationFinding(Severity.Error, lineNumber, lineSection, causeStartIndex, causeLength, error)
{
public AssemblyError(int lineNumber, LineSection lineSection, int causeStartIndex, int causeLength, ValidationError error)
: base(Severity.Error, lineNumber, lineSection, causeStartIndex, causeLength, error) { }
}
}
}
25 changes: 8 additions & 17 deletions src/MixAssembler/Finding/AssemblyFinding.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,18 @@
using MixLib.Misc;
using MixLib.Misc;

namespace MixAssembler.Finding
{

public abstract class AssemblyFinding
{
public int Length { get; private set; }
public int LineNumber { get; private set; }
public LineSection LineSection { get; private set; }
public Severity Severity { get; private set; }
public int StartCharIndex { get; private set; }
public abstract class AssemblyFinding(Severity severity, int lineNumber, LineSection section, int startCharIndex, int length)
{
public int Length => length;
public int LineNumber => lineNumber;
public LineSection LineSection => section;
public Severity Severity => severity;
public int StartCharIndex => startCharIndex;

public const int NoNumber = int.MinValue;

protected AssemblyFinding(Severity severity, int lineNumber, LineSection section, int startCharIndex, int length)
{
LineSection = section;
StartCharIndex = startCharIndex;
Length = length;
Severity = severity;
LineNumber = lineNumber;
}

public abstract string Message { get; }
}
}
11 changes: 3 additions & 8 deletions src/MixAssembler/Finding/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
namespace MixAssembler.Finding
{
public class AssemblyInfo : AssemblyFinding
public class AssemblyInfo(string message, int lineNumber, LineSection lineSection, int startCharIndex, int length)
: AssemblyFinding(MixLib.Misc.Severity.Info, lineNumber, lineSection, startCharIndex, length)
{
private readonly string message;

public AssemblyInfo(string message, int lineNumber, LineSection lineSection, int startCharIndex, int length)
: base(MixLib.Misc.Severity.Info, lineNumber, lineSection, startCharIndex, length)
=> this.message = message;

public override string Message
=> this.message;
=> message;
}
}
9 changes: 4 additions & 5 deletions src/MixAssembler/Finding/AssemblyWarning.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using MixLib.Misc;
using MixLib.Misc;

namespace MixAssembler.Finding
{
public class AssemblyWarning : ValidationFinding
public class AssemblyWarning(int lineNumber, LineSection lineSection, int causeStartIndex, int causeLength, ValidationError error)
: ValidationFinding(Severity.Warning, lineNumber, lineSection, causeStartIndex, causeLength, error)
{
public AssemblyWarning(int lineNumber, LineSection lineSection, int causeStartIndex, int causeLength, ValidationError error)
: base(Severity.Warning, lineNumber, lineSection, causeStartIndex, causeLength, error) { }
}
}
}
13 changes: 5 additions & 8 deletions src/MixAssembler/Finding/ValidationFinding.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
using MixLib.Misc;
using MixLib.Misc;

namespace MixAssembler.Finding
{
public class ValidationFinding : AssemblyFinding
public class ValidationFinding(Severity severity, int lineNumber, LineSection lineSection, int causeStartIndex, int causeLength, ValidationError error)
: AssemblyFinding(severity, lineNumber, lineSection, causeStartIndex, causeLength)
{
public ValidationError Error { get; private set; }

public ValidationFinding(Severity severity, int lineNumber, LineSection lineSection, int causeStartIndex, int causeLength, ValidationError error)
: base(severity, lineNumber, lineSection, causeStartIndex, causeLength)
=> Error = error;
public ValidationError Error => error;

public override string Message
=> Error.CompiledMessage;
=> Error.CompiledMessage;

}
}
37 changes: 14 additions & 23 deletions src/MixAssembler/Instruction/LoaderInstructionParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,19 @@

namespace MixAssembler.Instruction
{
/// <summary>
/// This class contains the parameters that are required to create an instance object of a specific loader instruction "template".
///
/// The (static) ParseAddressField method is to be called during the parsing of the MIXAL source (first assembly pass), to create a parameter object based on the loader instruction's address field.
/// The CreateInstance method should be called during the second assembly pass, to create the actual loader instruction instance.
/// </summary>
public class LoaderInstructionParameters : IInstructionParameters
/// <summary>
/// This class contains the parameters that are required to create an instance object of a specific loader instruction "template".
///
/// The (static) ParseAddressField method is to be called during the parsing of the MIXAL source (first assembly pass), to create a parameter object based on the loader instruction's address field.
/// The CreateInstance method should be called during the second assembly pass, to create the actual loader instruction instance.
/// </summary>
/// <remarks>
/// Constructor for this class.
/// </remarks>
/// <param name="value">The parameter value associated with the instruction. The type of the value depends on the loader instruction it is connected with</param>
/// <param name="textLength">The length (character count) of the value in the source code it was parsed from</param>
public class LoaderInstructionParameters(IValue value, int textLength) : IInstructionParameters
{
private readonly int textLength;
private readonly IValue value;

/// <summary>
/// Constructor for this class.
/// </summary>
/// <param name="value">The parameter value associated with the instruction. The type of the value depends on the loader instruction it is connected with</param>
/// <param name="textLength">The length (character count) of the value in the source code it was parsed from</param>
public LoaderInstructionParameters(IValue value, int textLength)
{
this.value = value;
this.textLength = textLength;
}

/// <summary>
/// Create a loader instruction instance with the parameters contained in this object.
/// </summary>
Expand All @@ -40,11 +31,11 @@ public InstructionInstanceBase CreateInstance(InstructionBase instruction, Assem

if (!value.IsValueDefined(status.LocationCounter))
{
status.ReportParsingError(LineSection.AddressField, 0, this.textLength, "value is not defined");
status.ReportParsingError(LineSection.AddressField, 0, textLength, "value is not defined");
return null;
}

return new LoaderInstruction.Instance(loaderInstruction, this.value.GetSign(status.LocationCounter), this.value.GetMagnitude(status.LocationCounter));
return new LoaderInstruction.Instance(loaderInstruction, value.GetSign(status.LocationCounter), value.GetMagnitude(status.LocationCounter));
}

/// <summary>
Expand Down
63 changes: 23 additions & 40 deletions src/MixAssembler/Instruction/MixInstructionParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,25 @@ namespace MixAssembler.Instruction
/// The (static) ParseAddressField method is to be called during the parsing of the MIXAL source (first assembly pass), to create a parameter object based on the MIX instruction's address field.
/// The CreateInstance method should be called during the second assembly pass, to create the actual MIX instruction instance.
/// </summary>
public class MixInstructionParameters : IInstructionParameters
public class MixInstructionParameters(IValue address, int indexPartCharIndex, IValue index, int fieldPartCharIndex, IValue field, int textLength) : IInstructionParameters
{
private readonly IValue address;
private readonly IValue field;
private readonly int fieldPartCharIndex;
private readonly IValue index;
private readonly int indexPartCharIndex;
private readonly int textLength;

private MixInstructionParameters(IValue address, int indexPartCharIndex, IValue index, int fieldPartCharIndex, IValue field, int textLength)
{
this.address = address;
this.index = index;
this.field = field;
this.indexPartCharIndex = indexPartCharIndex;
this.fieldPartCharIndex = fieldPartCharIndex;
this.textLength = textLength;
}

private bool AreValuesDefined(AssemblingStatus status)
{
if (!this.address.IsValueDefined(status.LocationCounter))
if (!address.IsValueDefined(status.LocationCounter))
{
status.ReportParsingError(LineSection.AddressField, 0, this.indexPartCharIndex, "address value undefined");
status.ReportParsingError(LineSection.AddressField, 0, indexPartCharIndex, "address value undefined");
return false;
}

if (!this.index.IsValueDefined(status.LocationCounter))
if (!index.IsValueDefined(status.LocationCounter))
{
status.ReportParsingError(LineSection.AddressField, this.indexPartCharIndex, this.fieldPartCharIndex - this.indexPartCharIndex, "index value undefined");
status.ReportParsingError(LineSection.AddressField, indexPartCharIndex, fieldPartCharIndex - indexPartCharIndex, "index value undefined");
return false;
}

if (!this.address.IsValueDefined(status.LocationCounter))
if (!address.IsValueDefined(status.LocationCounter))
{
status.ReportParsingError(LineSection.AddressField, this.fieldPartCharIndex, this.textLength - this.fieldPartCharIndex, "field value undefined");
status.ReportParsingError(LineSection.AddressField, fieldPartCharIndex, textLength - fieldPartCharIndex, "field value undefined");
return false;
}

Expand All @@ -67,11 +50,11 @@ public InstructionInstanceBase CreateInstance(InstructionBase instruction, Assem
if (!AreValuesDefined(status))
return null;

var addressMagnitude = this.address.GetMagnitude(status.LocationCounter);
var addressMagnitude = address.GetMagnitude(status.LocationCounter);
var word = new Word(MixInstruction.AddressByteCount);
if (addressMagnitude > word.MaxMagnitude)
{
status.ReportError(LineSection.AddressField, 0, this.indexPartCharIndex, new MixAssembler.Finding.ParsingError("address value " + addressMagnitude + " invalid", (int)-word.MaxMagnitude, (int)word.MaxMagnitude));
status.ReportError(LineSection.AddressField, 0, indexPartCharIndex, new Finding.ParsingError("address value " + addressMagnitude + " invalid", (int)-word.MaxMagnitude, (int)word.MaxMagnitude));
return null;
}

Expand All @@ -82,13 +65,13 @@ public InstructionInstanceBase CreateInstance(InstructionBase instruction, Assem

var instructionWord = new FullWord
{
Sign = this.address.GetSign(status.LocationCounter)
Sign = address.GetSign(status.LocationCounter)
};

for (int i = 0; i < word.ByteCount; i++)
instructionWord[i] = word[i];

instructionWord[MixInstruction.IndexByte] = (int)this.index.GetValue(status.LocationCounter);
instructionWord[MixInstruction.IndexByte] = (int)index.GetValue(status.LocationCounter);
instructionWord[MixInstruction.FieldSpecByte] = fieldSpecValue;
instructionWord[MixInstruction.OpcodeByte] = mixInstruction.Opcode;

Expand All @@ -100,15 +83,15 @@ public InstructionInstanceBase CreateInstance(InstructionBase instruction, Assem

private MixByte GetFieldSpecValue(AssemblingStatus status, MixInstruction mixInstruction)
{
var fieldValue = this.field.GetValue(status.LocationCounter);
var fieldValue = field.GetValue(status.LocationCounter);

switch (mixInstruction.MetaFieldSpec.Presence)
{
case MetaFieldSpec.Presences.Forbidden:
if (fieldValue == long.MinValue)
return mixInstruction.FieldSpec.MixByteValue;

status.ReportParsingError(LineSection.AddressField, this.fieldPartCharIndex, this.textLength - this.fieldPartCharIndex, "fieldspec forbidden for this instruction");
status.ReportParsingError(LineSection.AddressField, fieldPartCharIndex, textLength - fieldPartCharIndex, "fieldspec forbidden for this instruction");
return null;

case MetaFieldSpec.Presences.Optional:
Expand All @@ -121,7 +104,7 @@ private MixByte GetFieldSpecValue(AssemblingStatus status, MixInstruction mixIns
if (fieldValue != long.MinValue)
return (int)fieldValue;

status.ReportParsingError(LineSection.AddressField, this.fieldPartCharIndex, this.textLength - this.fieldPartCharIndex, "fieldspec mandatory for this instruction");
status.ReportParsingError(LineSection.AddressField, fieldPartCharIndex, textLength - fieldPartCharIndex, "fieldspec mandatory for this instruction");
return null;
}
return null;
Expand All @@ -130,12 +113,12 @@ private MixByte GetFieldSpecValue(AssemblingStatus status, MixInstruction mixIns
/// <summary>
/// Creates an instance of this class by parsing the address field of a MIX instruction.
/// </summary>
/// <param name="instruction">MixInstruction to parse the address field for. This method will throw an exception if this parameter is of a different instruction type.</param>
/// <param name="addressField">The address field to parse.</param>
/// <param name="status">ParsingStatus object reflecting the current state of the parse process</param>
///
/// <returns></returns>
public static IInstructionParameters ParseAddressField(InstructionBase instruction, string addressField, ParsingStatus status)
{
public static IInstructionParameters ParseAddressField(string addressField, ParsingStatus status)
{
var indexCharIndex = addressField.IndexOf(',');
var sectionCharIndex = addressField.IndexOf('(', Math.Max(indexCharIndex, 0));

Expand All @@ -145,7 +128,7 @@ public static IInstructionParameters ParseAddressField(InstructionBase instructi
if (indexCharIndex == -1)
indexCharIndex = sectionCharIndex;

var address = APartValue.ParseValue(addressField.Substring(0, indexCharIndex), 0, status);
var address = APartValue.ParseValue(addressField[..indexCharIndex], 0, status);
if (address == null)
{
status.ReportParsingError(0, indexCharIndex, "unable to parse address");
Expand Down Expand Up @@ -185,17 +168,17 @@ private void ReportInstanceErrors(AssemblingStatus status, MixInstruction.Instan
{
case InstanceValidationError.Sources.Address:
causeStartIndex = 0;
causeLength = this.indexPartCharIndex;
causeLength = indexPartCharIndex;
break;

case InstanceValidationError.Sources.Index:
causeStartIndex = this.indexPartCharIndex;
causeLength = this.fieldPartCharIndex - this.indexPartCharIndex;
causeStartIndex = indexPartCharIndex;
causeLength = fieldPartCharIndex - indexPartCharIndex;
break;

case InstanceValidationError.Sources.FieldSpec:
causeStartIndex = this.fieldPartCharIndex;
causeLength = this.textLength - this.fieldPartCharIndex;
causeStartIndex = fieldPartCharIndex;
causeLength = textLength - fieldPartCharIndex;
break;
}

Expand Down
Loading

0 comments on commit 9e171ad

Please sign in to comment.