Skip to content

Commit

Permalink
Fix MacroString encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
Soreepeong committed Aug 6, 2024
1 parent 7bf2bda commit 3b25a8a
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 56 deletions.
13 changes: 13 additions & 0 deletions src/Lumina/Text/Expressions/BaseExpression.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;

namespace Lumina.Text.Expressions;

Expand All @@ -24,6 +25,18 @@ public abstract class BaseExpression
/// <param name="stream">Target to write this expression to.</param>
public abstract void Encode( Stream stream );

/// <summary>Represent this expression as a part of macro string.</summary>
/// <param name="sb">Target string builder.</param>
public abstract void AppendMacroStringToStringBuilder( StringBuilder sb );

/// <inheritdoc/>
public override string ToString()
{
var sb = new StringBuilder();
AppendMacroStringToStringBuilder( sb );
return sb.ToString();
}

/// <summary>
/// Parse given Stream into an Expression.
/// </summary>
Expand Down
40 changes: 30 additions & 10 deletions src/Lumina/Text/Expressions/BinaryExpression.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;

namespace Lumina.Text.Expressions;

Expand Down Expand Up @@ -37,18 +38,37 @@ public BinaryExpression( ExpressionType typeByte, BaseExpression operand1, BaseE
public override ExpressionType ExpressionType { get; }

/// <inheritdoc />
public override string ToString()
public override void AppendMacroStringToStringBuilder( StringBuilder sb )
{
return ExpressionType switch
sb.Append( '[' );
Operand1.AppendMacroStringToStringBuilder( sb );

switch( ExpressionType )
{
ExpressionType.GreaterThanOrEqualTo => $"[{Operand1}>={Operand2}]",
ExpressionType.GreaterThan => $"[{Operand1}>{Operand2}]",
ExpressionType.LessThanOrEqualTo => $"[{Operand1}<={Operand2}]",
ExpressionType.LessThan => $"[{Operand1}<{Operand2}]",
ExpressionType.Equal => $"[{Operand1}=={Operand2}]",
ExpressionType.NotEqual => $"[{Operand1}!={Operand2}]",
_ => throw new NotImplementedException() // cannot reach, as this instance is immutable and this field is filtered from constructor
};
case ExpressionType.GreaterThanOrEqualTo:
sb.Append( ">=" );
break;
case ExpressionType.GreaterThan:
sb.Append( '>' );
break;
case ExpressionType.LessThanOrEqualTo:
sb.Append( "<=" );
break;
case ExpressionType.LessThan:
sb.Append( '<' );
break;
case ExpressionType.Equal:
sb.Append( "==" );
break;
case ExpressionType.NotEqual:
sb.Append( "!=" );
break;
default:
throw new NotSupportedException(); // cannot reach, as this instance is immutable and this field is filtered from constructor
}

Operand2.AppendMacroStringToStringBuilder( sb );
sb.Append( ']' );
}

/// <summary>
Expand Down
4 changes: 4 additions & 0 deletions src/Lumina/Text/Expressions/IntegerExpression.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;

namespace Lumina.Text.Expressions;

Expand Down Expand Up @@ -94,6 +95,9 @@ public static int CalculateSize( uint value )
/// <inheritdoc />
public override string ToString() => ( (int)Value ).ToString();

/// <inheritdoc />
public override void AppendMacroStringToStringBuilder( StringBuilder sb ) => sb.Append( (int) Value );

/// <summary>
/// Parse given Stream into an IntegerExpression.
/// </summary>
Expand Down
18 changes: 10 additions & 8 deletions src/Lumina/Text/Expressions/ParameterExpression.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;

namespace Lumina.Text.Expressions;

Expand Down Expand Up @@ -31,16 +32,17 @@ public ParameterExpression( ExpressionType typeByte, BaseExpression operand )
public override ExpressionType ExpressionType { get; }

/// <inheritdoc />
public override string ToString()
public override void AppendMacroStringToStringBuilder( StringBuilder sb )
{
return ExpressionType switch
sb.Append( ExpressionType switch
{
ExpressionType.IntegerParameter => $"lnum{Operand}",
ExpressionType.PlayerParameter => $"gnum{Operand}",
ExpressionType.StringParameter => $"lstr{Operand}",
ExpressionType.ObjectParameter => $"gstr{Operand}",
_ => throw new NotImplementedException() // cannot reach, as this instance is immutable and this field is filtered from constructor
};
ExpressionType.LocalNumber => "lnum",
ExpressionType.GlobalNumber => "gnum",
ExpressionType.LocalString => "lstr",
ExpressionType.GlobalString => "gstr",
_ => throw new NotSupportedException() // cannot reach, as this instance is immutable and this field is filtered from constructor
} );
Operand.AppendMacroStringToStringBuilder( sb );
}

/// <summary>
Expand Down
9 changes: 5 additions & 4 deletions src/Lumina/Text/Expressions/PlaceholderExpression.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;

namespace Lumina.Text.Expressions;

Expand Down Expand Up @@ -28,9 +29,9 @@ public PlaceholderExpression( ExpressionType expressionType )
public override void Encode( Stream stream ) => stream.WriteByte( (byte)ExpressionType );

/// <inheritdoc />
public override string ToString()
public override void AppendMacroStringToStringBuilder( StringBuilder sb )
{
return ExpressionType switch
sb.Append( ExpressionType switch
{
ExpressionType.Millisecond => "t_msec",
ExpressionType.Second => "t_sec",
Expand All @@ -41,8 +42,8 @@ public override string ToString()
ExpressionType.Month => "t_mon",
ExpressionType.Year => "t_year",
ExpressionType.StackColor => "stackcolor",
_ => $"Placeholder#{(byte)ExpressionType:X02}"
};
_ => $"Placeholder#{(byte) ExpressionType:X02}"
} );
}

/// <summary>
Expand Down
4 changes: 3 additions & 1 deletion src/Lumina/Text/Expressions/StringExpression.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Text;

namespace Lumina.Text.Expressions;

Expand Down Expand Up @@ -45,7 +46,8 @@ public override void Encode( Stream stream )
}

/// <inheritdoc />
public override string ToString() => Value?.ToString() ?? string.Empty;
public override void AppendMacroStringToStringBuilder( StringBuilder sb ) =>
Value.AppendMacroStringToStringBuilder( sb, true );

/// <summary>
/// Parse given Stream into a StringExpression.
Expand Down
40 changes: 40 additions & 0 deletions src/Lumina/Text/Payloads/BasePayload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,5 +256,45 @@ public override string ToString()
ex => ex is StringExpression se ? se.Value.ToMacroString() : ex.ToString()
) )})>";
}

internal void AppendMacroStringToStringBuilder( StringBuilder sb, bool forStringExpression )
{
if( PayloadType == PayloadType.Text )
{
foreach( var c in RawString )
{
switch( forStringExpression )
{
case true when c is '<' or '>' or '[' or ']' or '(' or ')' or ',' or '\\':
case false when c is '<' or '\\':
sb.Append( '\\' );
break;
}

sb.Append( c );
}

return;
}

sb.Append( $"<{( (MacroCode) PayloadType ).GetEncodeName()}" );
if( Expressions.Count > 0 )
{
sb.Append( '(' );
Expressions[ 0 ].AppendMacroStringToStringBuilder( sb );
if( Expressions.Count > 1 )
{
for( var i = 1; i < Expressions.Count; i++ )
{
sb.Append( ',' );
Expressions[ i ].AppendMacroStringToStringBuilder( sb );
}
}

sb.Append( ')' );
}

sb.Append( '>' );
}
}
}
83 changes: 65 additions & 18 deletions src/Lumina/Text/ReadOnly/ReadOnlySeExpressionSpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,43 +179,90 @@ public override int GetHashCode()

/// <inheritdoc/>
public override string ToString()
{
var sb = new StringBuilder();
AppendMacroStringToStringBuilder( sb );
return sb.ToString();
}

/// <summary>Writes the encodeable macro representation of this instance of <see cref="ReadOnlySePayloadSpan"/> to the given string builder.</summary>
/// <param name="sb">Target string builder.</param>
/// <returns>The encodeable macro representation.</returns>
public void AppendMacroStringToStringBuilder( StringBuilder sb )
{
if( Body.IsEmpty )
return "(?)";
{
sb.Append( "<expr: invalid empty>" );
return;
}

if( TryGetUInt( out var u32 ) )
return u32.ToString();
{
sb.Append( u32 );
return;
}

if( TryGetString( out var s ) )
return $"\"{s.ToString().Replace( "\\", "\\\\" ).Replace( "\"", "\\\"" )}\"";
{
s.AppendMacroStringToStringBuilder( sb, true );
return;
}

if( TryGetPlaceholderExpression( out var exprType ) )
{
if( ( (ExpressionType) exprType ).GetNativeName() is { } nativeName )
return nativeName;
return $"?x{exprType:X02}";
sb.Append( nativeName );
else
sb.Append( $"<expr: 0x{exprType:X02} is unsupported>" );
return;
}

if( TryGetParameterExpression( out exprType, out var e1 ) )
{
if( ( (ExpressionType) exprType ).GetNativeName() is { } nativeName )
return $"{nativeName}({e1.ToString()})";
throw new InvalidOperationException( "All native names must be defined for unary expressions." );
if( ( (ExpressionType) exprType ).GetNativeName() is not { } nativeName )
throw new InvalidOperationException( "All native names must be defined for unary expressions." );
sb.Append( nativeName );
e1.AppendMacroStringToStringBuilder( sb );
return;
}

if( TryGetBinaryExpression( out exprType, out e1, out var e2 ) )
{
if( ( (ExpressionType) exprType ).GetNativeName() is { } nativeName )
return $"{e1.ToString()} {nativeName} {e2.ToString()}";
throw new InvalidOperationException( "All native names must be defined for binary expressions." );
sb.Append( '[' );
e1.AppendMacroStringToStringBuilder( sb );
switch( (ExpressionType)exprType )
{
case ExpressionType.GreaterThanOrEqualTo:
sb.Append( ">=" );
break;
case ExpressionType.GreaterThan:
sb.Append( '>' );
break;
case ExpressionType.LessThanOrEqualTo:
sb.Append( "<=" );
break;
case ExpressionType.LessThan:
sb.Append( '<' );
break;
case ExpressionType.Equal:
sb.Append( "==" );
break;
case ExpressionType.NotEqual:
sb.Append( "!=" );
break;
default:
throw new NotSupportedException("should not happen");
}

e2.AppendMacroStringToStringBuilder( sb );
sb.Append( ']' );
return;
}

var sb = new StringBuilder();
sb.EnsureCapacity( 1 + 3 * Body.Length );
sb.Append( $"({Body[ 0 ]:X02}" );
for( var i = 1; i < Body.Length; i++ )
sb.Append( $" {Body[ i ]:X02}" );
sb.Append( ')' );
return sb.ToString();
sb.EnsureCapacity( sb.Length + 7 + 3 * Body.Length );
sb.Append( "<expr:" );
foreach (var t in Body)
sb.Append( $" {t:X02}" );
sb.Append( '>' );
}
}
Loading

0 comments on commit 3b25a8a

Please sign in to comment.