Skip to content

Commit

Permalink
Working through NeutralText.cs and Instruction.cs updates. Added Argu…
Browse files Browse the repository at this point in the history
…ment.cs and updated some enums. Documentation and tests
  • Loading branch information
tnunnink committed Oct 20, 2023
1 parent 45d84fc commit f571847
Show file tree
Hide file tree
Showing 36 changed files with 1,134 additions and 895 deletions.
114 changes: 62 additions & 52 deletions src/.idea/.idea.L5Sharp/.idea/workspace.xml

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src/L5Sharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "L5Sharp.Samples", "..\tests
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "L5Sharp", "L5Sharp\L5Sharp.csproj", "{927D481B-CB0E-4FA5-A5DC-98D8ECE5EF56}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "L5Sharp.Benchmarks", "..\tests\L5Sharp.Benchmarks\L5Sharp.Benchmarks.csproj", "{F52CE1E1-B8AC-431B-901F-55824D6F5E40}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -26,9 +28,14 @@ Global
{927D481B-CB0E-4FA5-A5DC-98D8ECE5EF56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{927D481B-CB0E-4FA5-A5DC-98D8ECE5EF56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{927D481B-CB0E-4FA5-A5DC-98D8ECE5EF56}.Release|Any CPU.Build.0 = Release|Any CPU
{F52CE1E1-B8AC-431B-901F-55824D6F5E40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F52CE1E1-B8AC-431B-901F-55824D6F5E40}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F52CE1E1-B8AC-431B-901F-55824D6F5E40}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F52CE1E1-B8AC-431B-901F-55824D6F5E40}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FED5FACA-5568-4A3F-94C0-536D9E36CA26} = {337B58B2-5647-4088-8CB3-50B3752B04D8}
{EBD410F5-C4E8-4D12-86B4-08B190B50B63} = {337B58B2-5647-4088-8CB3-50B3752B04D8}
{F52CE1E1-B8AC-431B-901F-55824D6F5E40} = {337B58B2-5647-4088-8CB3-50B3752B04D8}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions src/L5Sharp.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=INT/@EntryIndexedValue">INT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IO/@EntryIndexedValue">IO</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LEN/@EntryIndexedValue">LEN</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LINT/@EntryIndexedValue">LINT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LN/@EntryIndexedValue">LN</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LOG/@EntryIndexedValue">LOG</s:String>
Expand Down
106 changes: 84 additions & 22 deletions src/L5Sharp/Common/Argument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,91 @@ public class Argument
private readonly object _value;

/// <summary>
/// Creates a new <see cref="Argument"/> wrapping the provided immediate atomic value.
/// Creates a new <see cref="Argument"/> wrapping the object value.
/// </summary>
/// <param name="value">An <see cref="AtomicType"/> representing the argument.</param>
/// <param name="value">An object representing the argument.</param>
/// <exception cref="ArgumentNullException"><c>value</c> is <c>null</c>.</exception>
private Argument(AtomicType value)
private Argument(object value)
{
_value = value ?? throw new ArgumentNullException(nameof(value));
}

/// <summary>
/// Indicates whether the argument is an immediate atomic value.
/// </summary>
/// <value><c>true</c> if the underlying value is an <see cref="AtomicType"/> object; Otherwise, <c>false</c>.</value>
public bool IsAtomic => _value is AtomicType;

/// <summary>
/// Creates a new <see cref="Argument"/> wrapping the provided tag name reference.
/// Indicates whether the argument is an expression or combination of tag names, operators, and/or immediate values.
/// </summary>
/// <param name="value">A <see cref="TagName"/> representing the argument.</param>
/// <exception cref="ArgumentNullException"><c>value</c> is <c>null</c>.</exception>
private Argument(TagName value)
{
_value = value ?? throw new ArgumentNullException(nameof(value));
}
/// <value><c>true</c> if the underlying value is a <see cref="NeutralText"/> instance wrapping a complex expression;
/// Otherwise, <c>false</c>.</value>
public bool IsExpression => _value is NeutralText;

/// <summary>
/// Indicates whether the argument is an immediate atomic value.
/// Indicates whether the argument is an immediate value, either string literal or atomic value.
/// </summary>
/// <value><c>true</c> if the underlying value is an <see cref="AtomicType"/> object; Otherwise, <c>false</c>.</value>
public bool IsImmediate => _value is AtomicType;
/// <value><c>true</c> if the underlying value is an <see cref="AtomicType"/> or <see cref="string"/> object;
/// Otherwise, <c>false</c>.</value>
public bool IsImmediate => _value is AtomicType or string;

/// <summary>
/// Indicates whether the argument is an tag name reference.
/// </summary>
/// <value><c>true</c> if the underlying value is a <see cref="TagName"/> object; Otherwise, <c>false</c>.</value>
public bool IsTag => _value is TagName;

/// <summary>
/// Indicates whether the argument is a literal string value with the single quote identifiers.
/// </summary>
/// <value><c>true</c> if the underlying value is an <see cref="string"/> object; Otherwise, <c>false</c>.</value>
public bool IsString => _value is string;

/// <summary>
/// Represents an unknown argument that can be found in certain instruction text.
/// </summary>
/// <value>A <see cref="Argument"/> representing an unknown parameter.</value>
/// <remarks>This is literally the '?' character, as often seen in the TIMER instruction arguments.</remarks>
public static Argument Unknown => new("?");

/// <summary>
/// Represents an empty argument.
/// </summary>
/// <value>A <see cref="Argument"/> wrapping an empty string objet value.</value>
/// <remarks>
/// Some instruction have an empty/optional argument(s) (GSV) and therefore we need a way to represent
/// that value.
/// </remarks>
public static Argument Empty => new(string.Empty);

/// <summary>
/// Parses the string input into a valid <see cref="Argument"/> object.
/// </summary>
/// <param name="value">Teh string value to parse.</param>
/// <returns>A <see cref="Argument"/> representing the string input.</returns>
/// <exception cref="ArgumentException"><c>value</c> is null or empty</exception>
/// <remarks>This parse method expects the string to be an <see cref="AtomicType"/> immediate value,
/// a single <see cref="TagName"/> value, or an expression that can be represented as
/// <see cref="NeutralText"/> type.
/// </remarks>
public static Argument Parse(string? value)
{
//Empty value - lets not crash on empty or invalid arguments.
if (string.IsNullOrEmpty(value)) return Empty;

//Unknown value - Can be found in TON instructions.
if (value == "?") return Unknown;

//Literal string value - We need to intercept this before the Atomic.TryParse method to prevent overflow.
if (value.StartsWith('\'') && value.EndsWith('\'')) return new Argument(value);

//Immediate atomic value
if (Atomic.TryParse(value, out var atomicType) && atomicType is not null) return new Argument(atomicType);

//TagName or Expression otherwise
return TagName.IsTag(value) ? new Argument(new TagName(value)) : new Argument(new NeutralText(value));
}

/// <summary>
/// Implicitly converts the provided <see cref="TagName"/> to an <see cref="Argument"/>.
Expand All @@ -53,9 +108,9 @@ private Argument(TagName value)
/// <summary>
/// Implicitly converts the provided <see cref="TagName"/> to an <see cref="Argument"/>.
/// </summary>
/// <param name="tagName">The <see cref="TagName"/> object to convert.</param>
/// <param name="value">The <see cref="TagName"/> object to convert.</param>
/// <returns>A <see cref="Argument"/> object containing the value of the tag name.</returns>
public static implicit operator Argument(string tagName) => new(new TagName(tagName));
public static implicit operator Argument(string value) => Parse(value);

/// <summary>
/// Implicitly converts the provided value to an <see cref="Argument"/>.
Expand All @@ -70,14 +125,14 @@ private Argument(TagName value)
/// <param name="value">The object value to convert.</param>
/// <returns>An <see cref="Argument"/> containing the value of the provided object.</returns>
public static implicit operator Argument(sbyte value) => new(new SINT(value));

/// <summary>
/// Implicitly converts the provided value to an <see cref="Argument"/>.
/// </summary>
/// <param name="value">The object value to convert.</param>
/// <returns>An <see cref="Argument"/> containing the value of the provided object.</returns>
public static implicit operator Argument(byte value) => new(new USINT(value));

/// <summary>
/// Implicitly converts the provided value to an <see cref="Argument"/>.
/// </summary>
Expand All @@ -98,35 +153,35 @@ private Argument(TagName value)
/// <param name="value">The object value to convert.</param>
/// <returns>An <see cref="Argument"/> containing the value of the provided object.</returns>
public static implicit operator Argument(int value) => new(new DINT(value));

/// <summary>
/// Implicitly converts the provided value to an <see cref="Argument"/>.
/// </summary>
/// <param name="value">The object value to convert.</param>
/// <returns>An <see cref="Argument"/> containing the value of the provided object.</returns>
public static implicit operator Argument(uint value) => new(new UDINT(value));

/// <summary>
/// Implicitly converts the provided value to an <see cref="Argument"/>.
/// </summary>
/// <param name="value">The object value to convert.</param>
/// <returns>An <see cref="Argument"/> containing the value of the provided object.</returns>
public static implicit operator Argument(long value) => new(new LINT(value));

/// <summary>
/// Implicitly converts the provided value to an <see cref="Argument"/>.
/// </summary>
/// <param name="value">The object value to convert.</param>
/// <returns>An <see cref="Argument"/> containing the value of the provided object.</returns>
public static implicit operator Argument(ulong value) => new(new ULINT(value));

/// <summary>
/// Implicitly converts the provided value to an <see cref="Argument"/>.
/// </summary>
/// <param name="value">The object value to convert.</param>
/// <returns>An <see cref="Argument"/> containing the value of the provided object.</returns>
public static implicit operator Argument(float value) => new(new REAL(value));

/// <summary>
/// Implicitly converts the provided value to an <see cref="Argument"/>.
/// </summary>
Expand All @@ -147,6 +202,13 @@ private Argument(TagName value)
/// <param name="argument">The <see cref="Argument"/> object to convert.</param>
/// <returns>A <see cref="AtomicType"/> object representing the value of the argument.</returns>
public static explicit operator AtomicType(Argument argument) => (AtomicType) argument._value;

/// <summary>
/// Explicitly converts the provided <see cref="Argument"/> to an <see cref="NeutralText"/>.
/// </summary>
/// <param name="argument">The <see cref="Argument"/> object to convert.</param>
/// <returns>A <see cref="NeutralText"/> object representing the value of the argument.</returns>
public static explicit operator NeutralText(Argument argument) => (NeutralText) argument._value;

/// <inheritdoc />
public override bool Equals(object? obj) => _value.Equals(obj);
Expand Down
Loading

0 comments on commit f571847

Please sign in to comment.