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
2 changes: 1 addition & 1 deletion src/Hl7.Fhir.Base/FhirPath/EvaluationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public EvaluationContext(ITypedElement? resource, ITypedElement? rootResource, I
/// <summary>
/// A delegate that handles the output for the <c>trace()</c> function.
/// </summary>
public Action<string, IEnumerable<ITypedElement>>? Tracer { get; set; }
public Action<string?, IEnumerable<ITypedElement>>? Tracer { get; set; }
}

public static class EvaluationContextExtensions
Expand Down
365 changes: 182 additions & 183 deletions src/Hl7.Fhir.Base/FhirPath/Expressions/Invokee.cs

Large diffs are not rendered by default.

204 changes: 74 additions & 130 deletions src/Hl7.Fhir.Base/FhirPath/Expressions/SymbolTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,165 +6,109 @@
* available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE
*/

using Hl7.Fhir.ElementModel;
using System;
#nullable enable

using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Hl7.FhirPath.Expressions
{
namespace Hl7.FhirPath.Expressions;

public class SymbolTable
/// <summary>
/// Holds the functions and constants available for the FhirPath engine to bind to.
/// </summary>
public class SymbolTable
{
/// <summary>
/// An empty symbol table.
/// </summary>
public SymbolTable()
{
public SymbolTable()
{

}
// Nothing
}

public SymbolTable(SymbolTable parent)
{
Parent = parent;
}
/// <summary>
/// A local symbol table inside a parent scope.
/// </summary>
public SymbolTable(SymbolTable parent)
{
Parent = parent;
}

public int Count()
{
var cnt = _entries.Count;
if (Parent != null) cnt += Parent.Count();
/// <summary>
/// The number of entries in the symbol table, including the parent scope (if any).
/// </summary>
public int Count()
{
var cnt = _entries.Count;
if (Parent != null) cnt += Parent.Count();

return cnt;
}
return cnt;
}

internal Invokee First()
{
return _entries.Any() ? _entries.First().Body : (Parent?.First());
}
internal Invokee? First() => _entries.Any() ? _entries.First().Body : (Parent?.First());

public SymbolTable Parent { get; private set; }
/// <summary>
/// The parent scope for this symbol table.
/// </summary>
public SymbolTable? Parent { get; private set; }

[System.Diagnostics.DebuggerDisplay(@"\{{DebuggerDisplayValue()}}")]
private class TableEntry
[System.Diagnostics.DebuggerDisplay(@"\{{DebuggerDisplayValue()}}")]
private class TableEntry(CallSignature signature, Invokee body)
{
public string DebuggerDisplayValue()
{
public string DebuggerDisplayValue()
{
if (Signature != null)
{
var sb = new StringBuilder();
sb.Append(Signature.ReturnType.Name);
sb.Append(' ');
sb.Append(Signature.Name);
sb.Append(" (");
bool b = false;
foreach (var item in Signature.ArgumentTypes)
{
if (b)
sb.Append(", ");
sb.Append(item.Name);
b = true;
}
sb.Append(')');
return sb.ToString();
}
return null;
}

public CallSignature Signature { get; private set; }
public Invokee Body { get; private set; }
var sb = new StringBuilder();
sb.Append(Signature.ReturnType.Name);
sb.Append(' ');
sb.Append(Signature.Name);
sb.Append(" (");
bool b = false;

public TableEntry(CallSignature signature, Invokee body)
foreach (var item in Signature.ArgumentTypes)
{
Signature = signature;
Body = body;
if (b)
sb.Append(", ");
sb.Append(item.Name);
b = true;
}
}

private ConcurrentBag<TableEntry> _entries = new();
sb.Append(')');

internal void Add(CallSignature signature, Invokee body)
{
_entries.Add(new TableEntry(signature, body));
return sb.ToString();
}

public SymbolTable Filter(string name, int argCount)
{
var result = new SymbolTable
{
_entries = new(_entries.Where(e => e.Signature.Matches(name, argCount)))
};

if (Parent != null)
result.Parent = Parent.Filter(name, argCount);

return result;
}

internal Invokee DynamicGet(string name, IEnumerable<object> args)
{
var exactMatches = _entries.Where(e => e.Signature.DynamicExactMatches(name, args));
TableEntry entry = exactMatches.Union(_entries.Where(e => e.Signature.DynamicMatches(name, args))).FirstOrDefault();

if (entry == null && Parent != null) return Parent.DynamicGet(name, args);

return entry?.Body;
}
public CallSignature Signature { get; } = signature;
public Invokee Body { get; } = body;
}

private ConcurrentBag<TableEntry> _entries = [];

public static class SymbolTableExtensions
internal void Add(CallSignature signature, Invokee body)
{
public static void Add<R>(this SymbolTable table, string name, Func<R> func)
{
table.Add(new CallSignature(name, typeof(R)), InvokeeFactory.Wrap(func));
}

public static void Add<A, R>(this SymbolTable table, string name, Func<A, R> func, bool doNullProp = false)
{
if (typeof(A) != typeof(EvaluationContext))
table.Add(new CallSignature(name, typeof(R), typeof(A)), InvokeeFactory.Wrap(func, doNullProp));
else
table.Add(new CallSignature(name, typeof(R)), InvokeeFactory.Wrap(func, doNullProp));
}

public static void Add<A, B, R>(this SymbolTable table, string name, Func<A, B, R> func, bool doNullProp = false)
{
if (typeof(B) != typeof(EvaluationContext))
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B)), InvokeeFactory.Wrap(func, doNullProp));
else
table.Add(new CallSignature(name, typeof(R), typeof(A)), InvokeeFactory.Wrap(func, doNullProp));
}
_entries.Add(new TableEntry(signature, body));
}

public static void Add<A, B, C, R>(this SymbolTable table, string name, Func<A, B, C, R> func, bool doNullProp = false)
public SymbolTable Filter(string name, int argCount)
{
var result = new SymbolTable
{
if (typeof(C) != typeof(EvaluationContext))
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B), typeof(C)), InvokeeFactory.Wrap(func, doNullProp));
else
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B)), InvokeeFactory.Wrap(func, doNullProp));
}
_entries = new ConcurrentBag<TableEntry>(_entries.Where(e => e.Signature.Matches(name, argCount)))
};

public static void Add<A, B, C, D, R>(this SymbolTable table, string name, Func<A, B, C, D, R> func, bool doNullProp = false)
{
if (typeof(D) != typeof(EvaluationContext))
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B), typeof(C), typeof(D)), InvokeeFactory.Wrap(func, doNullProp));
else
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B), typeof(C)), InvokeeFactory.Wrap(func, doNullProp));
if (Parent != null)
result.Parent = Parent.Filter(name, argCount);

}
return result;
}

public static void AddLogic(this SymbolTable table, string name, Func<Func<bool?>, Func<bool?>, bool?> func)
{
table.Add(new CallSignature(name, typeof(bool?), typeof(object), typeof(Func<bool?>), typeof(Func<bool?>)),
InvokeeFactory.WrapLogic(func));
}
internal Invokee? DynamicGet(string name, IEnumerable<object> args)
{
var exactMatches = _entries.Where(e => e.Signature.DynamicExactMatches(name, args));
var entry = exactMatches.Union(_entries.Where(e => e.Signature.DynamicMatches(name, args))).FirstOrDefault();

public static void AddVar(this SymbolTable table, string name, object value)
{
table.AddVar(name, ElementNode.ForPrimitive(value));
}
if (entry == null && Parent != null) return Parent.DynamicGet(name, args);

public static void AddVar(this SymbolTable table, string name, ITypedElement value)
{
table.Add(new CallSignature(name, typeof(string)), InvokeeFactory.Return(value));
}
return entry?.Body;
}
}
}
75 changes: 75 additions & 0 deletions src/Hl7.Fhir.Base/FhirPath/Expressions/SymbolTableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2015, Firely (info@fire.ly) and contributors
* See the file CONTRIBUTORS for details.
*
* This file is licensed under the BSD 3-Clause license
* available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE
*/

#nullable enable

using Hl7.Fhir.ElementModel;
using System;

namespace Hl7.FhirPath.Expressions;

public static class SymbolTableExtensions
{
public static void Add<R>(this SymbolTable table, string name, Func<R> func)
{
table.Add(new CallSignature(name, typeof(R)), InvokeeFactory.Wrap(func));
}

public static void Add<A, R>(this SymbolTable table, string name, Func<A, R> func, bool doNullProp = false)
{
table.Add(
typeof(A) != typeof(EvaluationContext)
? new CallSignature(name, typeof(R), typeof(A))
: new CallSignature(name, typeof(R)), InvokeeFactory.Wrap(func, doNullProp));
}

public static void Add<A, B, R>(this SymbolTable table, string name, Func<A, B, R> func, bool doNullProp = false)
{
if (typeof(B) != typeof(EvaluationContext))
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B)), InvokeeFactory.Wrap(func, doNullProp));
else
table.Add(new CallSignature(name, typeof(R), typeof(A)), InvokeeFactory.Wrap(func, doNullProp));
}

public static void Add<A, B, C, R>(this SymbolTable table, string name, Func<A, B, C, R> func,
bool doNullProp = false)
{
if (typeof(C) != typeof(EvaluationContext))
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B), typeof(C)),
InvokeeFactory.Wrap(func, doNullProp));
else
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B)), InvokeeFactory.Wrap(func, doNullProp));
}

public static void Add<A, B, C, D, R>(this SymbolTable table, string name, Func<A, B, C, D, R> func,
bool doNullProp = false)
{
if (typeof(D) != typeof(EvaluationContext))
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B), typeof(C), typeof(D)),
InvokeeFactory.Wrap(func, doNullProp));
else
table.Add(new CallSignature(name, typeof(R), typeof(A), typeof(B), typeof(C)),
InvokeeFactory.Wrap(func, doNullProp));
}

public static void AddLogic(this SymbolTable table, string name, Func<Func<bool?>, Func<bool?>, bool?> func)
{
table.Add(new CallSignature(name, typeof(bool?), typeof(object), typeof(Func<bool?>), typeof(Func<bool?>)),
InvokeeFactory.WrapLogic(func));
}

public static void AddVar(this SymbolTable table, string name, object value)
{
table.AddVar(name, ElementNode.ForPrimitive(value));
}

public static void AddVar(this SymbolTable table, string name, ITypedElement value)
{
table.Add(new CallSignature(name, typeof(string)), InvokeeFactory.Return(value));
}
}
Loading