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
6 changes: 6 additions & 0 deletions src/LLTSharp/DataAccessors/TemplateArrayAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public TemplateArrayAccessor(IEnumerable<TemplateDataAccessor> array)
_array = array?.ToArray() ?? throw new ArgumentNullException(nameof(array));
}

public override string Type => "array";

public override TemplateDataAccessor Index(TemplateDataAccessor index, bool safe)
{
try
Expand Down Expand Up @@ -69,6 +71,8 @@ public override TemplateDataAccessor Operator(UnaryOperatorType type)
{
UnaryOperatorType.LogicalNot => new TemplateBooleanAccessor(!AsBoolean()),

UnaryOperatorType.LengthOf => new TemplateNumberAccessor(Length),

_ => throw new TemplateRuntimeException(
$"Unary operator '{type}' is not valid for array values",
dataAccessor: this)
Expand Down Expand Up @@ -104,6 +108,8 @@ BinaryOperatorType.GreaterThan or
$"Operator '{type}' cannot be applied to array values",
dataAccessor: this),

BinaryOperatorType.Coalesce => this,

_ => throw new TemplateRuntimeException(
$"Unknown operator type: {type}",
dataAccessor: this)
Expand Down
29 changes: 22 additions & 7 deletions src/LLTSharp/DataAccessors/TemplateBooleanAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ namespace LLTSharp.DataAccessors
/// </summary>
public class TemplateBooleanAccessor : TemplateDataAccessor
{
/// <summary>
/// Gets a singleton instance representing true.
/// </summary>
public static TemplateBooleanAccessor True { get; } = new TemplateBooleanAccessor(true);

/// <summary>
/// Gets a singleton instance representing false.
/// </summary>
public static TemplateBooleanAccessor False { get; } = new TemplateBooleanAccessor(false);

/// <summary>
/// Gets the value of the boolean accessor.
/// </summary>
Expand All @@ -22,6 +32,8 @@ public TemplateBooleanAccessor(bool value)
Value = value;
}

public override string Type => "boolean";

public override bool AsBoolean()
{
return Value;
Expand All @@ -47,15 +59,16 @@ public override string ToString(string? format = null)

public override TemplateDataAccessor Operator(UnaryOperatorType type)
{
switch (type)
return type switch
{
case UnaryOperatorType.Negate:
case UnaryOperatorType.LogicalNot:
return new TemplateBooleanAccessor(!AsBoolean());
UnaryOperatorType.Negate or UnaryOperatorType.LogicalNot => new TemplateBooleanAccessor(!AsBoolean()),

default:
throw new TemplateRuntimeException("Invalid operator type.", dataAccessor: this);
}
UnaryOperatorType.LengthOf => new TemplateNumberAccessor(Length),

_ => throw new TemplateRuntimeException(
$"Unary operator '{type}' is not valid for boolean values",
dataAccessor: this)
};
}

public override TemplateDataAccessor Operator(TemplateDataAccessor other, BinaryOperatorType type)
Expand Down Expand Up @@ -85,6 +98,8 @@ BinaryOperatorType.GreaterThan or
throw new TemplateRuntimeException(
$"Comparison operator '{type}' is not valid for boolean values"),

BinaryOperatorType.Coalesce => this,

_ => throw new TemplateRuntimeException(
$"Unknown operator type: {type}")
};
Expand Down
7 changes: 7 additions & 0 deletions src/LLTSharp/DataAccessors/TemplateDictionaryAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public TemplateDictionaryAccessor(IDictionary<string, TemplateDataAccessor> dict
Dictionary = new ReadOnlyDictionary<string, TemplateDataAccessor>(_dictionary);
}

public override string Type => "object";

public override TemplateDataAccessor Index(TemplateDataAccessor index, bool safe)
{
return Property(index.ToString(), safe);
Expand Down Expand Up @@ -78,6 +80,9 @@ public override TemplateDataAccessor Operator(UnaryOperatorType type)
return type switch
{
UnaryOperatorType.LogicalNot => new TemplateBooleanAccessor(!AsBoolean()),

UnaryOperatorType.LengthOf => new TemplateNumberAccessor(Length),

_ => throw new TemplateRuntimeException(
$"Unary operator '{type}' is not valid for dictionary values",
dataAccessor: this)
Expand Down Expand Up @@ -113,6 +118,8 @@ BinaryOperatorType.GreaterThan or
$"Operator '{type}' cannot be applied to dictionary values",
dataAccessor: this),

BinaryOperatorType.Coalesce => this,

_ => throw new TemplateRuntimeException(
$"Unknown operator type: {type}",
dataAccessor: this)
Expand Down
2 changes: 2 additions & 0 deletions src/LLTSharp/DataAccessors/TemplateNullAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class TemplateNullAccessor : TemplateDataAccessor
/// </summary>
private TemplateNullAccessor() { }

public override string Type => "null";

public override bool AsBoolean()
{
return false;
Expand Down
9 changes: 9 additions & 0 deletions src/LLTSharp/DataAccessors/TemplateNumberAccessor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

Expand All @@ -19,6 +20,8 @@ public TemplateNumberAccessor(double value)
Value = value;
}

public override string Type => "number";

public override bool AsBoolean()
{
return Value != 0;
Expand All @@ -39,7 +42,11 @@ public override TemplateDataAccessor Operator(UnaryOperatorType type)
return type switch
{
UnaryOperatorType.Negate => new TemplateNumberAccessor(-Value),

UnaryOperatorType.LogicalNot => new TemplateBooleanAccessor(!AsBoolean()),

UnaryOperatorType.LengthOf => new TemplateNumberAccessor(Length),

_ => throw new TemplateRuntimeException("Invalid operator type for number.", dataAccessor: this)
};
}
Expand Down Expand Up @@ -70,6 +77,8 @@ public override TemplateDataAccessor Operator(TemplateDataAccessor other, Binary
BinaryOperatorType.LogicalAnd => new TemplateBooleanAccessor(AsBoolean() && other.AsBoolean()),
BinaryOperatorType.LogicalOr => new TemplateBooleanAccessor(AsBoolean() || other.AsBoolean()),

BinaryOperatorType.Coalesce => this,

_ => throw new TemplateRuntimeException($"Unknown operator type: {type}")
};
}
Expand Down
2 changes: 2 additions & 0 deletions src/LLTSharp/DataAccessors/TemplateObjectAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public TemplateObjectAccessor(object target, DataAccessorCreationOptions options
_propertyAccessors = CreatePropertyAccessors(target, options);
}

public override string Type => "object";

private static IReadOnlyDictionary<string, Func<object?>> CreatePropertyAccessors(object obj, DataAccessorCreationOptions options)
{
var accessors = new Dictionary<string, Func<object?>>();
Expand Down
8 changes: 7 additions & 1 deletion src/LLTSharp/DataAccessors/TemplateStringAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public TemplateStringAccessor(string? value)
Value = value ?? string.Empty;
}

public override string Type => "string";

public override bool AsBoolean()
{
return !string.IsNullOrEmpty(Value);
Expand Down Expand Up @@ -74,7 +76,9 @@ public override TemplateDataAccessor Operator(UnaryOperatorType type)
return type switch
{
UnaryOperatorType.LogicalNot => new TemplateBooleanAccessor(!AsBoolean()),


UnaryOperatorType.LengthOf => new TemplateNumberAccessor(Length),

_ => throw new TemplateRuntimeException(
$"Unary operator '{type}' is not valid for string values",
dataAccessor: this)
Expand Down Expand Up @@ -108,6 +112,8 @@ BinaryOperatorType.Divide or
$"Arithmetic operator '{type}' cannot be applied to string values",
dataAccessor: this),

BinaryOperatorType.Coalesce => this,

_ => throw new TemplateRuntimeException(
$"Unknown operator type: {type}",
dataAccessor: this)
Expand Down
52 changes: 52 additions & 0 deletions src/LLTSharp/ExpressionNodes/TemplateArrayExpressionNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using LLTSharp.DataAccessors;

namespace LLTSharp.ExpressionNodes
{
/// <summary>
/// Represents an array creation expression node: <c>[expr1, expr2, ...]</c>.
/// Evaluates each element as an expression and returns a <see cref="TemplateArrayAccessor"/>.
/// </summary>
public class TemplateArrayExpressionNode : TemplateExpressionNode
{
private readonly TemplateExpressionNode[] _items;

/// <summary>
/// Gets the items of the array expression.
/// </summary>
public IReadOnlyList<TemplateExpressionNode> Items { get; }

/// <summary>
/// Initializes a new instance of the <see cref="TemplateArrayExpressionNode"/> class.
/// </summary>
/// <param name="items">The expressions for each element in the array.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="items"/> is null.</exception>
public TemplateArrayExpressionNode(IEnumerable<TemplateExpressionNode> items)
{
_items = items?.ToArray() ?? throw new ArgumentNullException(nameof(items));
Items = new ReadOnlyCollection<TemplateExpressionNode>(_items);
}

public override TemplateDataAccessor Evaluate(TemplateContextAccessor context)
{
var evaluatedItems = new TemplateDataAccessor[_items.Length];
for (int i = 0; i < _items.Length; i++)
{
var item = _items[i].Evaluate(context);
if (item == null)
throw new TemplateRuntimeException($"Array element at index {i} evaluated to null.", dataAccessor: null);
evaluatedItems[i] = item;
}
return new TemplateArrayAccessor(evaluatedItems);
}

public override string ToString()
{
return "[" + string.Join(", ", _items.Select(i => i.ToString())) + "]";
}
}
}
46 changes: 46 additions & 0 deletions src/LLTSharp/ExpressionNodes/TemplateHasPropertyExpressionNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using LLTSharp.DataAccessors;

namespace LLTSharp.ExpressionNodes
{
/// <summary>
/// Represents a property check expression node in a template.
/// </summary>
public class TemplateHasPropertyExpressionNode : TemplateExpressionNode
{
/// <summary>
/// Gets the child expression node that has the property to check.
/// </summary>
public TemplateExpressionNode Child { get; }

/// <summary>
/// Gets the name of the property to check.
/// </summary>
public TemplateExpressionNode PropertyName { get; }

/// <summary>
/// Creates a new instance of the <see cref="TemplateHasPropertyExpressionNode"/> class.
/// </summary>
/// <param name="child">The child expression node that has the property to check.</param>
/// <param name="propertyName">The name of the property to check.</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public TemplateHasPropertyExpressionNode(TemplateExpressionNode child, TemplateExpressionNode propertyName)
{
Child = child ?? throw new ArgumentNullException(nameof(child));
PropertyName = propertyName ?? throw new ArgumentException("Property name cannot be null or empty.", nameof(propertyName));
}

public override TemplateDataAccessor Evaluate(TemplateContextAccessor context)
{
var child = Child.Evaluate(context);
var propertyName = PropertyName.Evaluate(context).ToString();
return new TemplateBooleanAccessor(child.HasProperty(propertyName));
}

public override string ToString()
{
return $"{Child} ?: {PropertyName}";
}
}
}
51 changes: 51 additions & 0 deletions src/LLTSharp/ExpressionNodes/TemplateObjectExpressionNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using LLTSharp.DataAccessors;

namespace LLTSharp.ExpressionNodes
{
/// <summary>
/// Represents an object/dictionary creation expression node: <c>{ key: expr, ... }</c>.
/// Evaluates each value as an expression and returns a <see cref="TemplateDictionaryAccessor"/>.
/// </summary>
public class TemplateObjectExpressionNode : TemplateExpressionNode
{
private readonly KeyValuePair<TemplateExpressionNode, TemplateExpressionNode>[] _pairs;

/// <summary>
/// Gets the key-expression pairs of the object expression.
/// </summary>
public IReadOnlyList<KeyValuePair<TemplateExpressionNode, TemplateExpressionNode>> Pairs { get; }

/// <summary>
/// Initializes a new instance of the <see cref="TemplateObjectExpressionNode"/> class.
/// </summary>
/// <param name="pairs">The key-expression pairs for the object.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="pairs"/> is null.</exception>
public TemplateObjectExpressionNode(IEnumerable<KeyValuePair<TemplateExpressionNode, TemplateExpressionNode>> pairs)
{
_pairs = pairs?.ToArray() ?? throw new ArgumentNullException(nameof(pairs));
Pairs = new ReadOnlyCollection<KeyValuePair<TemplateExpressionNode, TemplateExpressionNode>>(_pairs);
}

public override TemplateDataAccessor Evaluate(TemplateContextAccessor context)
{
var dict = new Dictionary<string, TemplateDataAccessor>(_pairs.Length);
foreach (var pair in _pairs)
{
var key = pair.Key.Evaluate(context).ToString();
var value = pair.Value.Evaluate(context);
dict[key] = value;
}
return new TemplateDictionaryAccessor(dict);
}

public override string ToString()
{
return "{" + string.Join(", ", _pairs.Select(p => $"{p.Key}: {p.Value}")) + "}";
}
}
}
41 changes: 0 additions & 41 deletions src/LLTSharp/ExpressionNodes/TemplatePropertyExpressionNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,45 +51,4 @@ public override string ToString()
return $"{Child}.{PropertyName}";
}
}

/// <summary>
/// Represents a property check expression node in a template.
/// </summary>
public class TemplateHasPropertyExpressionNode : TemplateExpressionNode
{
/// <summary>
/// Gets the child expression node that has the property to check.
/// </summary>
public TemplateExpressionNode Child { get; }

/// <summary>
/// Gets the name of the property to check.
/// </summary>
public TemplateExpressionNode PropertyName { get; }

/// <summary>
/// Creates a new instance of the <see cref="TemplateHasPropertyExpressionNode"/> class.
/// </summary>
/// <param name="child">The child expression node that has the property to check.</param>
/// <param name="propertyName">The name of the property to check.</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public TemplateHasPropertyExpressionNode(TemplateExpressionNode child, TemplateExpressionNode propertyName)
{
Child = child ?? throw new ArgumentNullException(nameof(child));
PropertyName = propertyName ?? throw new ArgumentException("Property name cannot be null or empty.", nameof(propertyName));
}

public override TemplateDataAccessor Evaluate(TemplateContextAccessor context)
{
var child = Child.Evaluate(context);
var propertyName = PropertyName.Evaluate(context).ToString();
return new TemplateBooleanAccessor(child.HasProperty(propertyName));
}

public override string ToString()
{
return $"{Child} ? {PropertyName}";
}
}
}
Loading
Loading