Skip to content

Commit

Permalink
add runtime expression types for rich presence macros
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras committed Apr 3, 2024
1 parent 8a5ebbf commit 975b933
Show file tree
Hide file tree
Showing 15 changed files with 424 additions and 343 deletions.
5 changes: 5 additions & 0 deletions Source/Parser/Expressions/ExpressionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ public enum ExpressionType
/// A comparison of MemoryValues with a possible hit target.
/// </summary>
Requirement,

/// <summary>
/// A rich presence macro parameter.
/// </summary>
RichPresenceMacro,
}

internal static class ExpressionTypeExtension
Expand Down
46 changes: 46 additions & 0 deletions Source/Parser/Expressions/Trigger/RichPresenceLookupExpression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Text;

namespace RATools.Parser.Expressions.Trigger
{
internal class RichPresenceLookupExpression : RichPresenceMacroExpressionBase
{
public RichPresenceLookupExpression(StringConstantExpression name, ExpressionBase parameter)
: base(name, parameter)
{
}

public override string FunctionName { get { return "rich_presence_lookup"; } }

public DictionaryExpression Items { get; set; }

public StringConstantExpression Fallback { get; set; }

protected override bool Equals(ExpressionBase obj)
{
var that = obj as RichPresenceLookupExpression;
return (that != null && that.Name == Name && that.Parameter == Parameter && that.Fallback == Fallback && that.Items == Items);
}

internal override void AppendString(StringBuilder builder)
{
builder.Append("rich_presence_lookup(");
Name.AppendString(builder);
builder.Append(", ");
Parameter.AppendString(builder);
builder.Append(", { }");

if (Fallback != null && Fallback.Value != "")
{
builder.Append(", ");
Fallback.AppendString(builder);
}

builder.Append(')');
}

public override ErrorExpression Attach(RichPresenceBuilder builder)
{
return builder.AddLookupField(this, Name, Items, Fallback);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace RATools.Parser.Expressions.Trigger
{
internal abstract class RichPresenceMacroExpressionBase : ExpressionBase
{
protected RichPresenceMacroExpressionBase(StringConstantExpression name, ExpressionBase parameter)
: base(ExpressionType.RichPresenceMacro)
{
Name = name;
Parameter = parameter;
}

public abstract string FunctionName { get; }

public StringConstantExpression Name { get; private set; }

public ExpressionBase Parameter { get; private set; }

public abstract ErrorExpression Attach(RichPresenceBuilder builder);
}
}
88 changes: 88 additions & 0 deletions Source/Parser/Expressions/Trigger/RichPresenceValueExpression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using RATools.Data;
using System.Text;

namespace RATools.Parser.Expressions.Trigger
{
internal class RichPresenceValueExpression : RichPresenceMacroExpressionBase
{
public RichPresenceValueExpression(StringConstantExpression name, ExpressionBase parameter)
: base(name, parameter)
{
}

public override string FunctionName { get { return "rich_presence_value"; } }

public ValueFormat Format { get; set; }

public static ValueFormat ParseFormat(string format)
{
var valueFormat = Leaderboard.ParseFormat(format);
if (valueFormat == ValueFormat.None)
{
if (format == "ASCIICHAR")
valueFormat = ValueFormat.ASCIIChar;
else if (format == "UNICODECHAR")
valueFormat = ValueFormat.UnicodeChar;
}
return valueFormat;
}

public static string GetFormatString(ValueFormat format)
{
switch (format)
{
case ValueFormat.ASCIIChar:
return "ASCIICHAR";

case ValueFormat.UnicodeChar:
return "UNICODECHAR";

default:
return Leaderboard.GetFormatString(format);
}
}

protected override bool Equals(ExpressionBase obj)
{
var that = obj as RichPresenceValueExpression;
return (that != null && that.Format == Format && that.Name == Name && that.Parameter == Parameter);
}

internal override void AppendString(StringBuilder builder)
{
builder.Append("rich_presence_value(");
Name.AppendString(builder);
builder.Append(", ");
Parameter.AppendString(builder);

if (Format != ValueFormat.Value)
builder.AppendFormat(", \"{0}\"", GetFormatString(Format));

builder.Append(')');
}

public override ErrorExpression Attach(RichPresenceBuilder builder)
{
return builder.AddValueField(this, Name, Format);
}
}

internal class RichPresenceMacroExpression : RichPresenceValueExpression
{
public RichPresenceMacroExpression(StringConstantExpression name, ExpressionBase parameter)
: base(name, parameter)
{
}

public override string FunctionName { get { return "rich_presence_macro"; } }

internal override void AppendString(StringBuilder builder)
{
builder.Append("rich_presence_macro(");
Name.AppendString(builder);
builder.Append(", ");
Parameter.AppendString(builder);
builder.Append(')');
}
}
}
23 changes: 16 additions & 7 deletions Source/Parser/Functions/FormatFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public override bool Evaluate(InterpreterScope scope, out ExpressionBase result)
if (varargs == null)
return false;

result = Evaluate(stringExpression, varargs, false);
result = Evaluate(stringExpression, varargs, false, ProcessParameter);
return (result is StringConstantExpression);
}

Expand All @@ -60,15 +60,25 @@ private ArrayExpression EvaluateVarArgs(InterpreterScope scope, out ExpressionBa
var stringExpression = lastExpression as StringConstantExpression;
if (stringExpression != null)
{
result = Evaluate(stringExpression, varargs, false);
result = Evaluate(stringExpression, varargs, false, ProcessParameter);
if (result is ErrorExpression)
return null;
}

return varargs;
}

internal static ExpressionBase Evaluate(StringConstantExpression formatString, ArrayExpression parameters, bool ignoreMissing)
private static ErrorExpression ProcessParameter(StringBuilder builder, int index, ExpressionBase parameter)
{
if (!parameter.IsLiteralConstant)
return new ConversionErrorExpression(parameter, ExpressionType.StringConstant);

parameter.AppendStringLiteral(builder);
return null;
}

internal static ExpressionBase Evaluate(StringConstantExpression formatString, ArrayExpression parameters, bool ignoreMissing,
Func<StringBuilder, int, ExpressionBase, ErrorExpression> processParameter)
{
var builder = new StringBuilder();

Expand Down Expand Up @@ -118,10 +128,9 @@ internal static ExpressionBase Evaluate(StringConstantExpression formatString, A
var parameter = parameters.Entries[parameterIndex];
if (parameter != null)
{
if (!parameter.IsLiteralConstant)
return new ConversionErrorExpression(parameter, ExpressionType.StringConstant);

parameter.AppendStringLiteral(builder);
var error = processParameter(builder, parameterIndex, parameter);
if (error != null)
return error;
}
}

Expand Down
119 changes: 42 additions & 77 deletions Source/Parser/Functions/RichPresenceDisplayFunction.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using RATools.Data;
using RATools.Parser.Expressions;
using RATools.Parser.Expressions;
using RATools.Parser.Expressions.Trigger;
using RATools.Parser.Internal;
using System.Collections.Generic;
using System.Text;

namespace RATools.Parser.Functions
{
Expand Down Expand Up @@ -69,103 +69,68 @@ protected ArrayExpression EvaluateVarArgs(InterpreterScope scope, out Expression
if (varargs == null)
return null;

for (int parameterIndex = 0; parameterIndex < varargs.Entries.Count; parameterIndex++)
var stringExpression = lastExpression as StringConstantExpression;
if (stringExpression != null)
{
result = varargs.Entries[parameterIndex];
var functionCall = result as FunctionCallExpression;
if (functionCall != null)
{
if (!functionCall.Evaluate(scope, out result))
return null;
var richPresenceContext = scope.GetContext<RichPresenceDisplayContext>();

varargs.Entries[parameterIndex] = result;
}
else
{
var stringValue = result as StringConstantExpression;
if (stringValue == null)
result = FormatFunction.Evaluate(stringExpression, varargs, false,
(StringBuilder builder, int index, ExpressionBase parameter) =>
{
var combine = result as IMathematicCombineExpression;
if (combine != null)
{
result = combine.Combine(new StringConstantExpression(""), MathematicOperation.Add);
varargs.Entries[parameterIndex] = result;

stringValue = result as StringConstantExpression;
}

if (stringValue == null)
stringValue = new StringConstantExpression("{" + parameterIndex + "}");
}
// keep the placeholder - we'll need it when we serialize
builder.Append('{');
builder.Append(index);
builder.Append('}');
var richPresenceContext = scope.GetContext<RichPresenceDisplayContext>();
richPresenceContext.DisplayString.AddParameter(stringValue);
}
}
return ProcessParameter(parameter, index, richPresenceContext);
});

var stringExpression = lastExpression as StringConstantExpression;
if (stringExpression != null)
{
result = FormatFunction.Evaluate(stringExpression, varargs, false);
if (result is ErrorExpression)
return null;
}

return varargs;
}

internal class RichPresenceDisplayContext
{
public RichPresenceBuilder RichPresence { get; set; }
public RichPresenceBuilder.ConditionalDisplayString DisplayString { get; set; }
}

internal abstract class FunctionDefinition : FunctionDefinitionExpression
static ErrorExpression ProcessParameter(ExpressionBase parameter, int index, RichPresenceDisplayContext richPresenceContext)
{
public FunctionDefinition(string name)
: base(name)
var richPresenceMacro = parameter as RichPresenceMacroExpressionBase;
if (richPresenceMacro != null)
{
}
var error = richPresenceMacro.Attach(richPresenceContext.RichPresence);
if (error != null)
return error;

public override bool Evaluate(InterpreterScope scope, out ExpressionBase result)
{
var richPresenceContext = scope.GetContext<RichPresenceDisplayContext>();
if (richPresenceContext == null)
{
result = new ErrorExpression(Name.Name + " has no meaning outside of a rich_presence_display call");
return false;
}
var value = ValueBuilder.BuildValue(richPresenceMacro.Parameter, out error);
if (error != null)
return new ErrorExpression(richPresenceMacro.FunctionName + " call failed", richPresenceMacro) { InnerError = error };

return BuildMacro(richPresenceContext, scope, out result);
richPresenceContext.DisplayString.AddParameter(index, richPresenceMacro, value);
return null;
}

protected abstract bool BuildMacro(RichPresenceDisplayContext context, InterpreterScope scope, out ExpressionBase result);

protected static Value GetExpressionValue(InterpreterScope scope, out ExpressionBase result)
var stringValue = parameter as StringConstantExpression;
if (stringValue == null)
{
var expression = GetParameter(scope, "expression", out result);
if (expression == null)
return null;

var requirements = new List<Requirement>();
var context = new ValueBuilderContext { Trigger = requirements };
var triggerBuilderScope = new InterpreterScope(scope) { Context = context };
if (!expression.ReplaceVariables(triggerBuilderScope, out expression))
{
result = expression;
return null;
}

ErrorExpression error;
var value = ValueBuilder.BuildValue(expression, out error);
if (value == null)
var combine = parameter as IMathematicCombineExpression;
if (combine != null)
{
result = error;
return null;
var result = combine.Combine(new StringConstantExpression(""), MathematicOperation.Add);
stringValue = result as StringConstantExpression;
}

return value;
if (stringValue == null)
stringValue = new StringConstantExpression("{" + index + "}");
}

richPresenceContext.DisplayString.AddParameter(index, stringValue);
return null;
}

internal class RichPresenceDisplayContext
{
public RichPresenceBuilder RichPresence { get; set; }
public RichPresenceBuilder.ConditionalDisplayString DisplayString { get; set; }
}
}
}
Loading

0 comments on commit 975b933

Please sign in to comment.