1
0
forked from GitHub/gf-core

.NET binding to GF by Bjørnar Luteberget

This commit is contained in:
krasimir
2017-05-31 13:48:36 +00:00
parent 2a8d2806e4
commit e1cec06f74
15 changed files with 1509 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PGFSharp
{
// Brackets should only be constructed from the Concrete class.
// These classes just store the data, they do not own or use
// unmanaged memory (except in the builder class).
public interface IBracketChild {
bool IsString {get;}
string AsStringChild {get;}
Bracket AsBracketChild {get;}
}
public class Bracket : IBracketChild
{
public class StringChildBracket : IBracketChild {
string str;
internal StringChildBracket(string str) {
this.str = str;
}
public bool IsString => true;
public string AsStringChild => str;
public Bracket AsBracketChild {
get {
throw new NotImplementedException ();
}
}
public override string ToString () => AsStringChild;
}
internal class BracketBuilder {
internal Native.PgfLinFuncs LinFuncs { get; private set; }
private Stack<Bracket> stack = new Stack<Bracket> ();
private Bracket final = null;
internal BracketBuilder() {
LinFuncs = new Native.PgfLinFuncs {
symbol_token = SymbolToken,
begin_prase = BeginPhrase,
end_phrase = EndPhrase,
symbol_ne = null,
symbol_bind = null,
symbol_capit = null
};
}
// TODO: the Python wrapper discards begin/end phrase pairs
// which don't have any tokens. Is this correct and/or necessary?
private void SymbolToken(IntPtr self, IntPtr token) {
var str = Native.NativeString.StringFromNativeUtf8 (token);
stack.Peek ().AddChild (new StringChildBracket (str));
}
private void BeginPhrase(IntPtr self, IntPtr cat, int fid, int lindex, IntPtr fun) {
stack.Push (new Bracket ());
}
private void EndPhrase(IntPtr self, IntPtr cat, int fid, int lindex, IntPtr fun) {
var b = stack.Pop ();
b.CatName = Native.NativeString.StringFromNativeUtf8 (cat);
b.FunName = Native.NativeString.StringFromNativeUtf8 (fun);
b.FId = fid;
b.LIndex = lindex;
if (stack.Count == 0)
final = b;
else
stack.Peek ().AddChild (b);
}
public Bracket Build() {
return final;
}
}
private List<IBracketChild> _children = new List<IBracketChild> ();
private Bracket() {
}
private void AddChild(IBracketChild c) {
_children.Add(c);
}
public bool IsString => false;
public Bracket AsBracketChild => this;
public string AsStringChild {
get {
throw new NotImplementedException ();
}
}
public IEnumerable<IBracketChild> Children { get { return _children; } }
public string CatName { get; private set; }
public string FunName { get; private set; }
public int FId { get; private set; }
public int LIndex { get; private set; }
public override string ToString ()
{
return "(" + CatName + ":" + FId + " " + String.Join (" ", Children) + ")";
}
public string ToBracketsString => "{" + String.Join(" ",
Children.Select(c => (c is Bracket) ? ((Bracket)c).ToBracketsString : c.ToString() )
) + "}";
}
}

173
src/runtime/dotNet/Concr.cs Normal file
View File

@@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace PGFSharp
{
/// <summary>
/// Concrete grammar. All concrete grammars are available from the (Abstract) <see cref="Grammar"/> class.
/// </summary>
public class Concr
{
internal IntPtr Ptr { get; private set; }
/// <summary>
/// Abstract grammar for this language.
/// </summary>
public PGF PGF { get; private set; }
private Concr() { }
internal static Concr FromPtr(PGF g, IntPtr ptr)
{
var concr = new Concr();
concr.PGF = g;
concr.Ptr = ptr;
return concr;
}
/// <summary>
/// Name of the grammar.
/// </summary>
public string Name => Native.NativeString.StringFromNativeUtf8(Native.pgf_concrete_name(Ptr));
public override string ToString() => $"Concrete:{Name} of {PGF.Name}";
/// <summary>
/// Parse given input string in the concrete grammar.
/// </summary>
/// <param name="str">Input string to be parsed.</param>
/// <param name="cat">Category (Type) to parse.</param>
/// <param name="heuristics">Heuristic (see the GF C runtime docs).</param>
/// <param name="Callback1">Callback function.</param>
/// <param name="Callback2">Callback function.</param>
/// <returns>Enumerates pairs of (abstract grammar) expressions and corresponding probability.</returns>
public IEnumerable<Tuple<Expr, float>> Parse(string str, Type cat = null, double? heuristics = null,
Action Callback1 = null, Action Callback2 = null)
{
var parse_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(parse_pool);
cat = cat ?? PGF.StartCat;
using (var nativeStr = new Native.NativeString(str))
{
var result_pool = new NativeGU.NativeMemoryPool();
var callbackMap = Native.pgf_new_callbacks_map(this.Ptr, parse_pool.Ptr);
var iterator = Native.pgf_parse_with_heuristics(this.Ptr, cat.Ptr,
nativeStr.Ptr, heuristics ?? -1, callbackMap,
exn.Ptr, parse_pool.Ptr, result_pool.Ptr);
if (iterator == IntPtr.Zero || exn.IsRaised)
{
throw new ParseError();
}
else
{
foreach (var ptr in NativeGU.IteratorToIEnumerable(iterator, parse_pool.Ptr))
{
var exprProb = (Native.PgfExprProb)Marshal.PtrToStructure(ptr, typeof(Native.PgfExprProb));
yield return Tuple.Create(Expr.FromPtr(exprProb.expr, result_pool),
exprProb.prob);
}
}
}
}
/// <summary>
/// Linearize expression, i.e. produce a string in the concrete grammar from an expression in the abstract grammar.
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public string Linearize(Expr e)
{
var tmp_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(tmp_pool);
var buf = NativeGU.gu_new_string_buf(tmp_pool.Ptr);
var out_ = NativeGU.gu_string_buf_out(buf);
Native.pgf_linearize(Ptr, e.Ptr, out_, exn.Ptr);
if (exn.IsRaised)
{
throw new PGFError();
}
else
{
var cstr = NativeGU.gu_string_buf_freeze(buf, tmp_pool.Ptr);
return Native.NativeString.StringFromNativeUtf8(cstr);
}
}
/// <summary>
/// Get all possible linearization for an expression (see <see cref="Linearize(Expression)"/>).
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public IEnumerable<string> LinearizeAll(Expr e)
{
var tmp_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(tmp_pool);
var cts = Native.pgf_lzr_concretize(Ptr, e.Ptr, exn.Ptr, tmp_pool.Ptr);
if (exn.IsRaised || cts == IntPtr.Zero) throw new PGFError("Could not linearize the abstract tree.");
return NativeGU.IteratorToIEnumerable(cts, tmp_pool.Ptr).Select(LinearizeCnc);
}
private string LinearizeCnc(IntPtr cnc)
{
var tmp_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(tmp_pool);
var sbuf = NativeGU.gu_new_string_buf(tmp_pool.Ptr);
var out_ = NativeGU.gu_string_buf_out(sbuf);
var wrapped = Native.pgf_lzr_wrap_linref(cnc, tmp_pool.Ptr);
Native.pgf_lzr_linearize_simple(Ptr, wrapped, 0, out_, exn.Ptr, tmp_pool.Ptr);
if (exn.IsRaised) throw new PGFError("Could not linearize abstract tree.");
var cstr = NativeGU.gu_string_buf_freeze(sbuf, tmp_pool.Ptr);
return Native.NativeString.StringFromNativeUtf8(cstr);
}
/// <summary>
/// Get the bracketed (structured) linearization of an expression.
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public Bracket BracketedLinearize(Expr e)
{
var tmp_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(tmp_pool);
var cts = Native.pgf_lzr_concretize(Ptr, e.Ptr, exn.Ptr, tmp_pool.Ptr);
var ctree = IntPtr.Zero;
NativeGU.gu_enum_next(cts, ref ctree, tmp_pool.Ptr);
if (ctree == IntPtr.Zero)
{
return null;
}
ctree = Native.pgf_lzr_wrap_linref(ctree, tmp_pool.Ptr);
var builder = new Bracket.BracketBuilder();
var mem = Marshal.AllocHGlobal(Marshal.SizeOf<Native.PgfLinFuncs>());
Marshal.StructureToPtr<Native.PgfLinFuncs>(builder.LinFuncs, mem, false);
Native.pgf_lzr_linearize(Ptr, ctree, 0, ref mem, tmp_pool.Ptr);
var b = builder.Build();
Marshal.FreeHGlobal(mem);
return b;
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PGFSharp
{
[Serializable]
public class PGFError : Exception
{
public PGFError() { }
public PGFError(string message) : base(message) { }
public PGFError(string message, Exception inner) : base(message, inner) { }
protected PGFError(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context)
{ }
}
[Serializable]
public class ParseError : Exception
{
public ParseError() { }
public ParseError(string message) : base(message) { }
public ParseError(string message, Exception inner) : base(message, inner) { }
protected ParseError(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context)
{ }
}
[Serializable]
public class TypeError : Exception
{
public TypeError() { }
public TypeError(string message) : base(message) { }
public TypeError(string message, Exception inner) : base(message, inner) { }
protected TypeError(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context)
{ }
}
}

133
src/runtime/dotNet/Expr.cs Normal file
View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace PGFSharp
{
internal class UnsupportedExpr : Expr
{
internal UnsupportedExpr(IntPtr expr, NativeGU.NativeMemoryPool pool) : base(expr, pool) { }
public override R Accept<R>(IVisitor<R> visitor)
{
throw new NotImplementedException();
}
}
public abstract class Expr
{
internal IntPtr DataPtr => NativeGU.gu_variant_open(_ptr).Data; // PgfExprLit*
internal PgfExprTag Tag => (PgfExprTag)NativeGU.gu_variant_open(_ptr).Tag;
internal IntPtr MkStringVariant(byte tag, string s, ref IntPtr out_)
{
var size = Encoding.UTF8.GetByteCount(s);
IntPtr slitPtr = NativeGU.gu_alloc_variant(tag,
(UIntPtr)(size + 1), UIntPtr.Zero, ref out_, _pool.Ptr);
Native.NativeString.CopyToPreallocated(s, slitPtr);
return slitPtr;
}
/// <summary>
/// Read expression from string.
/// </summary>
/// <param name="exprStr"></param>
/// <returns></returns>
public Expr ReadExpr(string exprStr)
{
var tmp_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(tmp_pool);
var result_pool = new NativeGU.NativeMemoryPool();
using (var strNative = new Native.NativeString(exprStr))
{
var in_ = NativeGU.gu_data_in(strNative.Ptr, strNative.Size, tmp_pool.Ptr);
var expr = Native.pgf_read_expr(in_, result_pool.Ptr, exn.Ptr);
if (exn.IsRaised || expr == IntPtr.Zero)
{
throw new PGFError();
}
else
{
return Expr.FromPtr(expr, result_pool);
}
}
}
internal enum PgfExprTag
{
PGF_EXPR_ABS,
PGF_EXPR_APP,
PGF_EXPR_LIT,
PGF_EXPR_META,
PGF_EXPR_FUN,
PGF_EXPR_VAR,
PGF_EXPR_TYPED,
PGF_EXPR_IMPL_ARG,
PGF_EXPR_NUM_TAGS // not used
};
public interface IVisitor<R>
{
R VisitLiteralInt(int value);
R VisitLiteralFloat(double value);
R VisitLiteralString(string value);
R VisitApplication(string fname, Expr[] args);
//R VisitMetaVariable (int id); Dont' care about this for now...
// Remove this, Function objects use VisitApplication with empty args instead.
//R VisitFunction (string fname); // Will this be used?
}
public class Visitor<R> : IVisitor<R>
{
public Func<int, R> fVisitLiteralInt { get; set; } = null;
public R VisitLiteralInt(int x1) => fVisitLiteralInt(x1);
public Func<double, R> fVisitLiteralFlt { get; set; } = null;
public R VisitLiteralFloat(double x1) => fVisitLiteralFlt(x1);
public Func<string, R> fVisitLiteralStr { get; set; } = null;
public R VisitLiteralString(string x1) => fVisitLiteralStr(x1);
public Func<string, Expr[], R> fVisitApplication { get; set; } = null;
public R VisitApplication(string x1, Expr[] x2) => fVisitApplication(x1, x2);
}
public abstract R Accept<R>(IVisitor<R> visitor);
internal IntPtr _ptr = IntPtr.Zero;
internal NativeGU.NativeMemoryPool _pool;
internal IntPtr Ptr => _ptr;
internal Expr() { }
internal Expr(IntPtr ptr, NativeGU.NativeMemoryPool pool)
{
_ptr = ptr; _pool = pool;
}
// Factories
private static Dictionary<PgfExprTag, Func<IntPtr, NativeGU.NativeMemoryPool, Expr>> factories =
new Dictionary<PgfExprTag, Func<IntPtr, NativeGU.NativeMemoryPool, Expr>>{
{ PgfExprTag.PGF_EXPR_LIT, (e, p) => LiteralExpr.FromPtr (e, p) },
{ PgfExprTag.PGF_EXPR_APP, (e, p) => new ApplicationExpr (e, p) },
{ PgfExprTag.PGF_EXPR_FUN, (e, p) => new FunctionExpr (e, p) },
{ PgfExprTag.PGF_EXPR_META, (e, p) => new MetaVariableExpr (e, p) }
};
internal static Expr FromPtr(IntPtr expr, NativeGU.NativeMemoryPool pool)
{
var Tag = (PgfExprTag)NativeGU.gu_variant_open(expr).Tag;
if (factories.ContainsKey(Tag))
{
return factories[Tag](expr, pool);
}
else
return new UnsupportedExpr(expr, pool);
}
public override string ToString() =>
Native.ReadString((output,exn) => Native.pgf_print_expr(_ptr, IntPtr.Zero, 0, output, exn.Ptr));
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Runtime.InteropServices;
namespace PGFSharp
{
/*public class Abs : Expression
{
public Abs ()
{
}
}
*/
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
namespace PGFSharp
{
public class ApplicationExpr : Expr
{
public override R Accept<R> (IVisitor<R> visitor)
{
var args = new List<Expr> ();
var expr = this;
while (expr.Function is ApplicationExpr) {
args.Add (expr.Argument);
expr = expr.Function as ApplicationExpr;
}
args.Add (expr.Argument);
if (!(expr.Function is FunctionExpr))
throw new ArgumentException ();
args.Reverse ();
return visitor.VisitApplication ((expr.Function as FunctionExpr).Name, args.ToArray());
}
[StructLayout(LayoutKind.Sequential)]
private struct PgfExprApp {
public IntPtr Function;
public IntPtr Argument;
}
private PgfExprApp Data => Marshal.PtrToStructure<PgfExprApp>(DataPtr);
public Expr Function => Expr.FromPtr(Data.Function, _pool);
public Expr Argument => Expr.FromPtr(Data.Argument, _pool);
internal ApplicationExpr(IntPtr ptr, NativeGU.NativeMemoryPool pool) : base(ptr, pool) { }
public ApplicationExpr(string fname, IEnumerable<Expr> args)
{
_pool = new NativeGU.NativeMemoryPool();
MkStringVariant((byte)PgfExprTag.PGF_EXPR_FUN, fname, ref _ptr);
foreach (var arg in args) {
var fun = _ptr;
var exprApp = NativeGU.gu_alloc_variant((byte)PgfExprTag.PGF_EXPR_APP,
(UIntPtr)Marshal.SizeOf<PgfExprApp>(), UIntPtr.Zero, ref _ptr, _pool.Ptr);
Native.EditStruct<PgfExprApp> (exprApp, (ref PgfExprApp app) => {
app.Function = fun;
app.Argument = arg.Ptr;
});
}
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Linq;
using System.Collections.Generic;
namespace PGFSharp
{
public class FunctionExpr : Expr
{
public override R Accept<R> (IVisitor<R> visitor)
{
return visitor.VisitApplication (Name, new Expr[] {});
}
internal FunctionExpr (IntPtr expr, NativeGU.NativeMemoryPool pool) : base(expr,pool) {}
public string Name => Native.NativeString.StringFromNativeUtf8(DataPtr);
}
}

View File

@@ -0,0 +1,127 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace PGFSharp
{
public class LiteralStringExpr : LiteralExpr
{
internal LiteralStringExpr(IntPtr expr, NativeGU.NativeMemoryPool pool) : base(expr, pool) { }
public LiteralStringExpr(string s) : base()
{
_pool = new NativeGU.NativeMemoryPool();
var exprTag = (byte)(int)PgfExprTag.PGF_EXPR_LIT;
IntPtr litPtr = NativeGU.gu_alloc_variant(exprTag,
(UIntPtr)Marshal.SizeOf<NativePgfExprLit>(), UIntPtr.Zero, ref _ptr, _pool.Ptr);
Native.EditStruct<NativePgfExprLit>(litPtr, (ref NativePgfExprLit lit) => {
MkStringVariant((byte)PgfLiteralTag.PGF_LITERAL_STR, s, ref lit.lit);
});
}
public override R Accept<R>(IVisitor<R> visitor)
{
return visitor.VisitLiteralString(Value);
}
public string Value => Native.NativeString.StringFromNativeUtf8(LitDataPtr);
}
public class LiteralIntExpr : LiteralExpr
{
internal LiteralIntExpr(IntPtr expr, NativeGU.NativeMemoryPool pool) : base(expr, pool) { }
public LiteralIntExpr(int val) : base()
{
Initialize<NativePgfLiteralInt>(PgfLiteralTag.PGF_LITERAL_INT,
(ref NativePgfLiteralInt ilit) => ilit.val = val);
}
public override R Accept<R>(IVisitor<R> visitor)
{
return visitor.VisitLiteralInt(Value);
}
public int Value => Marshal.PtrToStructure<NativePgfLiteralInt>(LitDataPtr).val;
[StructLayout(LayoutKind.Sequential)]
private struct NativePgfLiteralInt { public int val; }
}
public class LiteralFloatExpr : LiteralExpr
{
internal LiteralFloatExpr(IntPtr expr, NativeGU.NativeMemoryPool pool) : base(expr, pool) { }
public LiteralFloatExpr(double val) : base()
{
Initialize<NativePgfLiteralFlt>(PgfLiteralTag.PGF_LITERAL_FLT,
(ref NativePgfLiteralFlt flit) => flit.val = val);
}
public override R Accept<R>(IVisitor<R> visitor)
{
return visitor.VisitLiteralFloat(Value);
}
public double Value => Marshal.PtrToStructure<NativePgfLiteralFlt>(LitDataPtr).val;
[StructLayout(LayoutKind.Sequential)]
private struct NativePgfLiteralFlt { public double val; }
}
public abstract class LiteralExpr : Expr
{
internal LiteralExpr(IntPtr expr, NativeGU.NativeMemoryPool pool) : base(expr, pool) { }
internal LiteralExpr() { }
internal new static Expr FromPtr(IntPtr expr, NativeGU.NativeMemoryPool pool)
{
var dataPtr = NativeGU.gu_variant_open(expr).Data; // PgfExprLit*
var data = Marshal.PtrToStructure<NativePgfExprLit>(dataPtr);
var literalTag = (PgfLiteralTag)NativeGU.gu_variant_open(data.lit).Tag;
switch(literalTag)
{
case PgfLiteralTag.PGF_LITERAL_STR:
return new LiteralStringExpr(expr, pool);
case PgfLiteralTag.PGF_LITERAL_INT:
return new LiteralIntExpr(expr, pool);
case PgfLiteralTag.PGF_LITERAL_FLT:
return new LiteralFloatExpr(expr, pool);
default:
throw new ArgumentException();
}
}
internal void Initialize<TNative>(PgfLiteralTag litTag, Native.StructAction<TNative> setValue, UIntPtr? size = null) {
_pool = new NativeGU.NativeMemoryPool();
var exprTag = (byte)(int)PgfExprTag.PGF_EXPR_LIT;
IntPtr litPtr = NativeGU.gu_alloc_variant ( exprTag,
(UIntPtr)Marshal.SizeOf<NativePgfExprLit>(), UIntPtr.Zero, ref _ptr, _pool.Ptr);
Native.EditStruct<NativePgfExprLit> (litPtr, (ref NativePgfExprLit lit) => {
IntPtr ilitPtr = NativeGU.gu_alloc_variant ((byte)litTag,
(UIntPtr)Marshal.SizeOf<TNative> (), UIntPtr.Zero, ref lit.lit, _pool.Ptr);
Native.EditStruct<TNative>(ilitPtr, setValue);
});
}
// Deref DatPtr to det PgfExprLit.
private NativePgfExprLit Data => Marshal.PtrToStructure<NativePgfExprLit>(DataPtr);
private PgfLiteralTag LiteralTag => (PgfLiteralTag) NativeGU.gu_variant_open(Data.lit).Tag;
internal IntPtr LitDataPtr => NativeGU.gu_variant_open(Data.lit).Data;
internal enum PgfLiteralTag {
PGF_LITERAL_STR,
PGF_LITERAL_INT,
PGF_LITERAL_FLT,
PGF_LITERAL_NUM_TAGS
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativePgfExprLit { public IntPtr lit; }
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Runtime.InteropServices;
namespace PGFSharp
{
public class MetaVariableExpr : Expr {
internal MetaVariableExpr() {
_pool = new NativeGU.NativeMemoryPool();
IntPtr exprMetaPtr = NativeGU.gu_alloc_variant ((byte)PgfExprTag.PGF_EXPR_META,
(UIntPtr)Marshal.SizeOf <NativePgfExprMeta>(), UIntPtr.Zero, ref _ptr, _pool.Ptr);
Native.EditStruct<NativePgfExprMeta> (exprMetaPtr, (ref NativePgfExprMeta m) => m.Id = 0);
}
internal MetaVariableExpr(IntPtr ptr, NativeGU.NativeMemoryPool pool) : base(ptr, pool) { }
public int Id => Data.Id;
private NativePgfExprMeta Data => Marshal.PtrToStructure<NativePgfExprMeta>(DataPtr);
public override R Accept<R> (IVisitor<R> visitor)
{
// return visitor.VisitMetaVariable (Id);
// Not supported yet.
throw new NotImplementedException();
}
[StructLayout(LayoutKind.Sequential)]
private struct NativePgfExprMeta { public int Id; }
}
}

View File

@@ -0,0 +1,306 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Portable grammar format PInvoke functions.
/// </summary>
namespace PGFSharp
{
internal static class Native
{
internal class NativeString : IDisposable
{
public IntPtr Ptr { get; private set; }
public int Size { get; private set; }
public NativeString(string s)
{
Ptr = NativeUtf8FromString(s);
Size = Encoding.UTF8.GetByteCount(s);
}
public void Dispose()
{
Marshal.FreeHGlobal(Ptr);
Ptr = IntPtr.Zero;
}
public static IntPtr NativeUtf8FromString(string managedString)
{
int len = Encoding.UTF8.GetByteCount(managedString);
IntPtr nativeUtf8 = Marshal.AllocHGlobal(len + 1);
CopyToPreallocated(managedString, nativeUtf8, len);
return nativeUtf8;
}
public static void CopyToPreallocated(string managedString, IntPtr ptr, int? len = null)
{
if (len == null) len = Encoding.UTF8.GetByteCount(managedString);
byte[] buffer = new byte[len.Value + 1];
Encoding.UTF8.GetBytes(managedString, 0, managedString.Length, buffer, 0);
Marshal.Copy(buffer, 0, ptr, buffer.Length);
}
public static string StringFromNativeUtf8(IntPtr nativeUtf8)
{
int len = 0;
while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
byte[] buffer = new byte[len];
Marshal.Copy(nativeUtf8, buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer);
}
}
public delegate void StructAction<T>(ref T st);
public static void EditStruct<T>(IntPtr ptr, StructAction<T> f)
{
var str = Marshal.PtrToStructure<T>(ptr);
f(ref str);
Marshal.StructureToPtr<T>(str, ptr, false);
}
const string LIBNAME = "pgf.dll";
const CallingConvention CC = CallingConvention.Cdecl;
#region Basic
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_read([MarshalAs(UnmanagedType.LPStr)] string fpath, IntPtr pool, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_read_in(IntPtr in_, IntPtr pool, IntPtr tmp_pool, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_concrete_load(IntPtr concr, IntPtr in_, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_abstract_name(IntPtr pgf);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_concrete_name(IntPtr concr);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_start_cat(IntPtr pgf, IntPtr pool);
#endregion
#region Linearization
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_linearize(IntPtr concr, IntPtr expr, IntPtr out_, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_lzr_concretize(IntPtr concr, IntPtr expr, IntPtr err, IntPtr tmp_pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_lzr_wrap_linref(IntPtr ctree, IntPtr tmp_pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_lzr_linearize(IntPtr concr, IntPtr ctree, int lin_idx, ref IntPtr funcs, IntPtr tmp_pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_lzr_linearize_simple(IntPtr concr, IntPtr ctree, int lin_idx, IntPtr out_, IntPtr exn, IntPtr tmp_pool);
#endregion
#region Iteration
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_iter_languages(IntPtr pgf, ref GuMapItor itor, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_iter_categories(IntPtr pgf, ref GuMapItor itor, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_iter_functions(IntPtr pgf, ref GuMapItor itor, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_iter_functions_by_cat(IntPtr pgf, IntPtr catNameStr, ref GuMapItor itor, IntPtr err);
#endregion
#region Type
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_function_type(IntPtr pgf, IntPtr funNameStr);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_read_type(IntPtr in_, IntPtr pool, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_print_type(IntPtr expr, IntPtr ctxt, int prec, IntPtr output, IntPtr err);
#endregion
#region Expression
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void pgf_print_expr(IntPtr expr, IntPtr ctxt, int prec, IntPtr output, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_read_expr(IntPtr in_, IntPtr pool, IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_compute(IntPtr pgf, IntPtr expr, IntPtr err, IntPtr tmp_pool, IntPtr res_pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_generate_all(IntPtr pgf, IntPtr type, IntPtr err, IntPtr iter_pool, IntPtr out_pool);
#endregion
#region Concrete
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_parse_with_heuristics(IntPtr concr, IntPtr cat, IntPtr sentence,
double heuristics, IntPtr callbacks, IntPtr exn,
IntPtr parsePl, IntPtr exprPl);
#endregion
#region Callbacks
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr pgf_new_callbacks_map(IntPtr concr, IntPtr pool);
#endregion
//public delegate void GuMapItorFn(IntPtr self, [MarshalAs(UnmanagedType.LPStr)] string key, IntPtr value, IntPtr err);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void GuMapItorFn(IntPtr self, IntPtr key, IntPtr value, IntPtr err);
/*
public delegate void GuFinalizerFn(IntPtr self);
[StructLayout(LayoutKind.Sequential)]
public struct GuFinalizer
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public GuFinalizerFn fn;
}
[StructLayout(LayoutKind.Sequential)]
public struct PgfConcr
{
public IntPtr name, abstr, cflags, printnames,
ccats, fun_indices, coerce_idx, cncfuns,
sequences, cnccats;
public int total_cats;
public IntPtr pool;
GuFinalizer fin;
}*/
[StructLayout(LayoutKind.Sequential)]
public struct GuMapItor
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public GuMapItorFn fn;
}
[StructLayout(LayoutKind.Sequential)]
public struct PgfExprProb
{
public float prob;
public IntPtr expr; // PgfExpr type (not pointer, but typedef PgfExpr -> GuVariant -> uintptr_t)
}
#region Linearization callbacks
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LinFuncSymbolToken(IntPtr self, IntPtr token);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LinFuncBeginPhrase(IntPtr self, IntPtr cat, int fid, int lindex, IntPtr fun);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LinFuncEndPhrase(IntPtr self, IntPtr cat, int fid, int lindex, IntPtr fun);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LinFuncSymbolNonexistant(IntPtr self);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LinFuncSymbolBinding(IntPtr self);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LinFuncSymbolCapitalization(IntPtr self);
[StructLayout(LayoutKind.Sequential)]
public struct PgfLinFuncs
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public LinFuncSymbolToken symbol_token;
[MarshalAs(UnmanagedType.FunctionPtr)]
public LinFuncBeginPhrase begin_prase;
[MarshalAs(UnmanagedType.FunctionPtr)]
public LinFuncEndPhrase end_phrase;
[MarshalAs(UnmanagedType.FunctionPtr)]
public LinFuncSymbolNonexistant symbol_ne;
[MarshalAs(UnmanagedType.FunctionPtr)]
public LinFuncSymbolBinding symbol_bind;
[MarshalAs(UnmanagedType.FunctionPtr)]
public LinFuncSymbolCapitalization symbol_capit;
}
#endregion
/*
[StructLayout(LayoutKind.Sequential)]
public struct PGFClosure
{
public GuMapItor fn;
public IntPtr grammar;
public IntPtr obj;
}*/
public static string ReadString(Action<IntPtr, NativeGU.NativeExceptionContext> f)
{
var pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(pool);
var sbuf = NativeGU.gu_new_string_buf(pool.Ptr);
var output = NativeGU.gu_string_buf_out(sbuf);
f(output, exn);
if (exn.IsRaised) throw new Exception();
var strPtr = NativeGU.gu_string_buf_freeze(sbuf, pool.Ptr);
var str = Native.NativeString.StringFromNativeUtf8(strPtr);
return str;
}
public delegate void MapIterFunc(IntPtr pgf, ref GuMapItor fn, IntPtr err);
public delegate void IterNameFunc(IntPtr pgf, IntPtr name, ref GuMapItor fn, IntPtr err);
public class IterFuncCurryName
{
private IntPtr name;
private IterNameFunc func;
public IterFuncCurryName(IterNameFunc f, IntPtr name)
{
this.func = f;
this.name = name;
}
public void IterFunc(IntPtr pgf, ref GuMapItor fn, IntPtr err)
{
func(pgf, name, ref fn, err);
}
}
public static void MapIter(MapIterFunc iter, IntPtr _pgf, Action<string, IntPtr> action)
{
var pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(pool);
var f = new GuMapItor()
{
fn = (self, key, value, _err) =>
{
action(Native.NativeString.StringFromNativeUtf8(key), value);
if (exn.IsRaised) throw new Exception();
}
};
iter(_pgf, ref f, exn.Ptr);
}
}
}

View File

@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace PGFSharp
{
internal static class NativeGU
{
const string LIBNAME = "gu.dll";
const CallingConvention CC = CallingConvention.Cdecl;
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr gu_new_pool();
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr gu_new_exn(IntPtr pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void gu_pool_free(IntPtr pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr get_gu_null_variant();
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr gu_string_buf_out(IntPtr sbuf);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr gu_new_string_buf(IntPtr pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr gu_data_in(IntPtr str, int len, IntPtr pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr gu_string_buf_freeze(IntPtr sbuf, IntPtr pool);
[DllImport(LIBNAME, CallingConvention = CC)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool gu_exn_is_raised(IntPtr err);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern void gu_enum_next(IntPtr enum_, ref IntPtr outPtr, IntPtr pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern GuVariantInfo gu_variant_open(IntPtr variant);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr gu_alloc_variant(byte tag, UIntPtr size, UIntPtr align, ref IntPtr out_, IntPtr pool);
[DllImport(LIBNAME, CallingConvention = CC)]
public static extern IntPtr gu_make_variant(byte tag, UIntPtr size, UIntPtr align, ref IntPtr init, IntPtr pool);
[StructLayout(LayoutKind.Sequential)]
public struct GuVariantInfo
{
public int Tag;
public IntPtr Data;
}
[StructLayout(LayoutKind.Sequential)]
public struct GuSeq
{
public UIntPtr length;
}
public static uint SeqLength(IntPtr seqptr)
{
var seq = Marshal.PtrToStructure<GuSeq>(seqptr);
return (uint)seq.length;
}
public static T gu_seq_index<T>(IntPtr seq, int index)
{
var dataPtr = seq + Marshal.SizeOf<GuSeq>();
var hypoPtr = dataPtr + index * Marshal.SizeOf<T>();
var hypo = Marshal.PtrToStructure<T>(hypoPtr);
return hypo;
}
public class NativeMemoryPool
{
private IntPtr _ptr;
internal IntPtr Ptr => _ptr;
public NativeMemoryPool()
{
_ptr = gu_new_pool();
if (_ptr == IntPtr.Zero) throw new Exception();
}
~NativeMemoryPool()
{
gu_pool_free(_ptr);
_ptr = IntPtr.Zero;
}
}
public class NativeExceptionContext
{
private IntPtr _ptr;
internal IntPtr Ptr => _ptr;
public NativeExceptionContext(NativeMemoryPool pool)
{
_ptr = gu_new_exn(pool.Ptr);
if (_ptr == IntPtr.Zero) throw new Exception();
}
public bool IsRaised => gu_exn_is_raised(_ptr);
}
public static IEnumerable<IntPtr> IteratorToIEnumerable(IntPtr iterator, IntPtr pool)
{
IntPtr ptr = IntPtr.Zero;
NativeGU.gu_enum_next(iterator, ref ptr, pool);
while (ptr != IntPtr.Zero)
{
yield return ptr;
NativeGU.gu_enum_next(iterator, ref ptr, pool);
}
}
}
}

157
src/runtime/dotNet/PGF.cs Normal file
View File

@@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace PGFSharp
{
/// <summary>
/// Grammatical Framework grammar.
/// </summary>
public class PGF
{
private PGF() { }
IntPtr _ptr;
NativeGU.NativeMemoryPool pool;
/// <summary>
/// Read grammar from PGF file.
/// </summary>
/// <param name="fn">filename</param>
/// <returns></returns>
public static PGF ReadPGF(string fn)
{
var obj = new PGF();
var exn = new NativeGU.NativeExceptionContext(new NativeGU.NativeMemoryPool());
obj.pool = new NativeGU.NativeMemoryPool();
obj._ptr = Native.pgf_read(fn, obj.pool.Ptr, exn.Ptr);
if (exn.IsRaised)
{
throw new PGFError($"Could not read PGF from file {fn}. ({System.IO.Directory.GetCurrentDirectory()})");
}
return obj;
}
public override string ToString() => $"Grammar:{Name}, {String.Join(", ", Languages.Keys)}";
/// <summary>
/// Name of the abstract grammar.
/// </summary>
public string Name => Native.NativeString.StringFromNativeUtf8(Native.pgf_abstract_name(_ptr));
/// <summary>
/// Default category of the grammar.
/// </summary>
public Type StartCat => Type.FromPtr(Native.pgf_start_cat(_ptr, pool.Ptr), pool);
/// <summary>
/// All concrete grammars in the language.
/// </summary>
public Dictionary<string, Concr> Languages
{
get
{
var dict = new Dictionary<string, Concr>();
Native.MapIter(Native.pgf_iter_languages, _ptr, (k, v) => dict[k] = Concr.FromPtr(this, dereference(v)));
return dict;
}
}
private IntPtr dereference(IntPtr ptr)
{
return (IntPtr)Marshal.PtrToStructure(ptr, typeof(IntPtr));
}
/// <summary>
/// All categories in the abstract grammar.
/// </summary>
public IEnumerable<string> Categories => GetStringList(Native.pgf_iter_categories);
/// <summary>
/// All functions in the abstract grammar.
/// </summary>
public IEnumerable<string> Functions => GetStringList(Native.pgf_iter_functions);
/// <summary>
/// All functions producing the given category name.
/// </summary>
/// <param name="catName"></param>
/// <returns></returns>
public IEnumerable<string> FunctionByCategory(string catName)
{
using (var str = new Native.NativeString(catName))
{
return GetStringList(new Native.IterFuncCurryName(Native.pgf_iter_functions_by_cat, str.Ptr).IterFunc);
}
}
/// <summary>
/// Get type from function name.
/// </summary>
/// <param name="funName"></param>
/// <returns></returns>
public Type FunctionType(string funName)
{
using (var str = new Native.NativeString(funName))
{
var typePtr = Native.pgf_function_type(_ptr, str.Ptr);
if (typePtr == IntPtr.Zero) throw new NullReferenceException();
return Type.FromPtr(typePtr, pool);
}
}
/// <summary>
/// Reduce expression.
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
public Expr Compute(Expr expr)
{
var tmp_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(tmp_pool);
var result_pool = new NativeGU.NativeMemoryPool();
var newExpr = Native.pgf_compute(_ptr, expr.Ptr, exn.Ptr, pool.Ptr, result_pool.Ptr);
if (exn.IsRaised || newExpr == IntPtr.Zero)
{
throw new PGFError("Could not reduce expression.");
}
else
{
return Expr.FromPtr(newExpr, result_pool);
}
}
/// <summary>
/// Enumerate all expressions in the given category.
/// </summary>
/// <param name="cat"></param>
/// <returns></returns>
public IEnumerable<Expr> GenerateAll(Type cat = null)
{
cat = cat ?? StartCat;
var tmp_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(tmp_pool);
var result_pool = new NativeGU.NativeMemoryPool();
IntPtr ptr = IntPtr.Zero;
var iterator = Native.pgf_generate_all(this._ptr, cat.Ptr, exn.Ptr, tmp_pool.Ptr, result_pool.Ptr);
return NativeGU.IteratorToIEnumerable(iterator, tmp_pool.Ptr).Select(p =>
{
var exprProb = Marshal.PtrToStructure<Native.PgfExprProb>(ptr);
return Expr.FromPtr(exprProb.expr, result_pool);
});
}
private IEnumerable<string> GetStringList(Native.MapIterFunc f)
{
var c = new List<string>();
Native.MapIter(f, _ptr, (k, v) => c.Add(k));
return c;
}
}
}

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{81C13B1B-FE00-4A56-A831-964D55032CDD}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PGF</RootNamespace>
<AssemblyName>PGFSharp</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Bracket.cs" />
<Compile Include="Concr.cs" />
<Compile Include="Exceptions.cs" />
<Compile Include="Native.cs" />
<Compile Include="NativeGU.cs" />
<Compile Include="PGF.cs" />
<Compile Include="Type.cs" />
<Compile Include="Expr.cs" />
<Compile Include="Expr\Literal.cs" />
<Compile Include="Expr\MetaVariable.cs" />
<Compile Include="Expr\Application.cs" />
<Compile Include="Expr\Function.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ItemGroup>
<Folder Include="Expression\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PGF")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("81c13b1b-fe00-4a56-a831-964d55032cdd")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("3.8.0.0")]
[assembly: AssemblyFileVersion("3.8.0.0")]

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace PGFSharp
{
/// <summary>
/// A GF type.
/// </summary>
public class Type
{
private IntPtr _ptr;
internal IntPtr Ptr => _ptr;
private NativeGU.NativeMemoryPool _pool;
private Type() { }
internal static Type FromPtr(IntPtr type, NativeGU.NativeMemoryPool pool)
{
var t = new Type();
t._ptr = type;
t._pool = pool;
return t;
}
public override string ToString() =>
Native.ReadString((output,exn) => Native.pgf_print_type(_ptr, IntPtr.Zero, 0, output, exn.Ptr));
private PgfType Data => Marshal.PtrToStructure<PgfType>(_ptr);
/// <summary>
/// Read type from string.
/// </summary>
/// <param name="typeStr"></param>
/// <returns></returns>
public Type ReadType(string typeStr)
{
var tmp_pool = new NativeGU.NativeMemoryPool();
var exn = new NativeGU.NativeExceptionContext(tmp_pool);
var result_pool = new NativeGU.NativeMemoryPool();
using (var strNative = new Native.NativeString(typeStr))
{
var in_ = NativeGU.gu_data_in(strNative.Ptr, strNative.Size, tmp_pool.Ptr);
var typ = Native.pgf_read_type(in_, result_pool.Ptr, exn.Ptr);
if (exn.IsRaised || typ == IntPtr.Zero)
{
throw new PGFError();
}
else
{
return Type.FromPtr(typ, result_pool);
}
}
}
/// <summary>
/// Get the hypotheses of a type (function argument types).
/// </summary>
public IEnumerable<Type> Hypotheses
{
get
{
var n_hypos = NativeGU.SeqLength(Data.hypos);
for (int i = 0; i < n_hypos; i++)
{
var hypo = NativeGU.gu_seq_index<PgfHypo>(Data.hypos, i);
var type = Type.FromPtr(hypo.type, this._pool);
yield return type;
}
}
}
[StructLayout(LayoutKind.Sequential)]
private struct PgfType
{
public IntPtr hypos; // GuSeq of PgfHypo
public IntPtr cid;
public UIntPtr n_exprs;
public IntPtr exprs;
}
[StructLayout(LayoutKind.Sequential)]
private struct PgfHypo
{
public int pgfBindType; // enum
public IntPtr cid; // PgfCId (string)
public IntPtr type; // PgfType*
}
}
}