From 3da3e70f650e077e252d5d2b0003e4a625da37d7 Mon Sep 17 00:00:00 2001
From: Dan Hirsch <thequux@upstandinghackers.com>
Date: Sat, 4 Jan 2014 23:08:44 +0100
Subject: [PATCH] Got action and attr_bool working

---
 lib/tsgencsharp.pl                            |   2 +-
 src/bindings/dotnet/ext/hammer.cs             |  33 +++++-
 src/bindings/dotnet/test/hammer_hand_tests.cs |  27 ++++-
 src/bindings/dotnet/test/hammer_tests.cs      | 106 +++++++++---------
 src/bindings/dotnet/test/test_support.cs      |   8 ++
 5 files changed, 111 insertions(+), 65 deletions(-)

diff --git a/lib/tsgencsharp.pl b/lib/tsgencsharp.pl
index 1a750128..a31ffd02 100644
--- a/lib/tsgencsharp.pl
+++ b/lib/tsgencsharp.pl
@@ -151,7 +151,7 @@ pp_byte_seq_r([X|Xs]) --> !,
     pp_byte_seq_r(Xs).
 
 pp_parse_result(char(C)) --> !,
-    "(System.UInt64)",
+    %"(System.UInt64)",
     pp_parser(char(C)).
 pp_parse_result(seq(Args)) --> !,
     "new object[]{ ", pp_result_seq(Args), "}".
diff --git a/src/bindings/dotnet/ext/hammer.cs b/src/bindings/dotnet/ext/hammer.cs
index 00f217fe..fa7de568 100644
--- a/src/bindings/dotnet/ext/hammer.cs
+++ b/src/bindings/dotnet/ext/hammer.cs
@@ -122,12 +122,17 @@ namespace Hammer
   public class Hammer
   {
     internal static IDictionary tag_to_action;
+    internal static ulong charify_action;
     internal static HTokenType tt_dotnet;
     static Hammer()
     {
       tt_dotnet = hammer.h_allocate_token_type("com.upstandinghackers.hammer.dotnet.tagged");
       hammer.h_set_dotnet_tagged_token_type(tt_dotnet);
       tag_to_action = new System.Collections.Hashtable();
+      charify_action = RegisterAction(x => {
+          //System.Console.WriteLine(x.GetType());
+          return char.ConvertFromUtf32((int)(ulong)x)[0];
+        });
     }
     
     internal static ulong RegisterAction(HAction action)
@@ -137,6 +142,18 @@ namespace Hammer
       return newAction;
     }
     
+    internal static ulong RegisterPredicate(HPredicate predicate)
+    {
+      ulong newPredicate = (ulong)tag_to_action.Count;
+      tag_to_action[newPredicate] = predicate;
+      return newPredicate;
+    }
+    
+    internal static Parser CharParser(Parser p)
+    {
+      return new Parser(hammer.h_tag(p.wrapped, charify_action)).Pin(p);
+    }
+
     internal static byte[] ToBytes(string s)
     {
       // Probably not what you want unless you're parsing binary data.
@@ -192,7 +209,7 @@ namespace Hammer
 
     public static Parser Ch(byte ch)
     {
-      return new Parser(hammer.h_ch(ch));
+      return CharParser(new Parser(hammer.h_ch(ch)));
       
     }
     public static Parser Ch(char ch)
@@ -202,12 +219,12 @@ namespace Hammer
 
     public static Parser Ch_range(byte c1, byte c2)
     {
-      return new Parser(hammer.h_ch_range(c1, c2));
+      return CharParser(new Parser(hammer.h_ch_range(c1, c2)));
     }
 
     public static Parser Ch_range(char c1, char c2)
     {
-      return new Parser(hammer.h_ch_range((byte)c1, (byte)c2));
+      return CharParser(new Parser(hammer.h_ch_range((byte)c1, (byte)c2)));
     }
 
     public static Parser Int_range(Parser p, System.Int64 i1, System.Int64 i2)
@@ -230,7 +247,7 @@ namespace Hammer
       unsafe {
         fixed(byte* b = &charset[0])
           {
-            return new Parser(hammer.h_in((IntPtr)b, (uint)charset.Length));
+            return CharParser(new Parser(hammer.h_in((IntPtr)b, (uint)charset.Length)));
           }
       }
     }
@@ -240,7 +257,7 @@ namespace Hammer
       unsafe {
         fixed(byte* b = &charset[0])
           {
-            return new Parser(hammer.h_not_in((IntPtr)b, (uint)charset.Length));
+            return CharParser(new Parser(hammer.h_not_in((IntPtr)b, (uint)charset.Length)));
           }
       }
     }
@@ -277,7 +294,6 @@ namespace Hammer
     public static Parser Nothing_p() {return new Parser(hammer.h_nothing_p());}
     public static Parser Epsilon_p() {return new Parser(hammer.h_epsilon_p());}
 
-    
     // 1-arg parsers
     public static Parser Ignore(Parser p)
     {
@@ -362,6 +378,11 @@ namespace Hammer
       ulong actionNo = Hammer.RegisterAction(action);
       return new Parser(hammer.h_tag(p.wrapped, actionNo)).Pin(p).Pin(action);
     }
+    public static Parser AttrBool(Parser p, HPredicate predicate)
+    {
+      ulong predNo = Hammer.RegisterPredicate(predicate);
+      return new Parser(hammer.h_tag(p.wrapped, predNo)).Pin(p).Pin(predicate);
+    }
   }
   
 }
\ No newline at end of file
diff --git a/src/bindings/dotnet/test/hammer_hand_tests.cs b/src/bindings/dotnet/test/hammer_hand_tests.cs
index 0d885283..c6aaac7b 100644
--- a/src/bindings/dotnet/test/hammer_hand_tests.cs
+++ b/src/bindings/dotnet/test/hammer_hand_tests.cs
@@ -7,11 +7,28 @@ namespace Hammer.Test
     [Test]
     public void TestAction()
     {
-      Parser parser = Hammer.Action(Hammer.Sequence(Hammer.Choice(Hammer.Token("a"),
-                                                                  Hammer.Token("A")),
-                                                    Hammer.Choice(Hammer.Token("b"),
-                                                                  Hammer.Token("B"))),
-                                    (HAction)(x => char.ToUpper(((string)x)[0])));
+      Parser parser = Hammer.Action(Hammer.Sequence(Hammer.Choice(Hammer.Ch('a'),
+                                                                  Hammer.Ch('A')),
+                                                    Hammer.Choice(Hammer.Ch('b'),
+                                                                  Hammer.Ch('B'))),
+                                    (HAction)(x => string.Join(",",(object[])x)));
+      CheckParseOK(parser, "ab", "a,b");
+      CheckParseOK(parser, "AB", "A,B");
+      CheckParseFail(parser, "XX");
+    }
+    [Test]
+    public void TestAttrBool()
+    {
+      Parser parser = Hammer.AttrBool(Hammer.Many1(Hammer.Choice(Hammer.Ch('a'),
+                                                                 Hammer.Ch('b'))),
+                                      (HPredicate)(x => { 
+                                          object[] elems = (object[])x;
+                                          return elems.Length > 1 && (char)elems[0] == (char)elems[1];
+                                        }));
+      
+      CheckParseOK(parser, "aa", new object[]{ 'a','a' });
+      CheckParseOK(parser, "bb", new object[]{ 'b','b' });
+      CheckParseFail(parser, "ab");
                                                                   
     }
   }
diff --git a/src/bindings/dotnet/test/hammer_tests.cs b/src/bindings/dotnet/test/hammer_tests.cs
index ce464135..ac0ac9e2 100644
--- a/src/bindings/dotnet/test/hammer_tests.cs
+++ b/src/bindings/dotnet/test/hammer_tests.cs
@@ -13,14 +13,14 @@ namespace Hammer.Test {
         public void TestCh() {
             Parser parser;
             parser = Hammer.Ch(0xa2);
-              CheckParseOK(parser, "\xa2", (System.UInt64)'\xa2');
+              CheckParseOK(parser, "\xa2", '\xa2');
               CheckParseFail(parser, "\xa3");
         }
         [Test]
         public void TestCh_range() {
             Parser parser;
             parser = Hammer.Ch_range(0x61, 0x63);
-              CheckParseOK(parser, "b", (System.UInt64)'b');
+              CheckParseOK(parser, "b", 'b');
               CheckParseFail(parser, "d");
         }
         [Test]
@@ -94,10 +94,10 @@ namespace Hammer.Test {
         public void TestWhitespace() {
             Parser parser;
             parser = Hammer.Whitespace(Hammer.Ch(0x61));
-              CheckParseOK(parser, "a", (System.UInt64)'a');
-              CheckParseOK(parser, " a", (System.UInt64)'a');
-              CheckParseOK(parser, "  a", (System.UInt64)'a');
-              CheckParseOK(parser, "\x09a", (System.UInt64)'a');
+              CheckParseOK(parser, "a", 'a');
+              CheckParseOK(parser, " a", 'a');
+              CheckParseOK(parser, "  a", 'a');
+              CheckParseOK(parser, "\x09a", 'a');
               CheckParseFail(parser, "_a");
             parser = Hammer.Whitespace(Hammer.End_p());
               CheckParseOK(parser, "", null);
@@ -108,7 +108,7 @@ namespace Hammer.Test {
         public void TestLeft() {
             Parser parser;
             parser = Hammer.Left(Hammer.Ch(0x61), Hammer.Ch(0x20));
-              CheckParseOK(parser, "a ", (System.UInt64)'a');
+              CheckParseOK(parser, "a ", 'a');
               CheckParseFail(parser, "a");
               CheckParseFail(parser, " ");
               CheckParseFail(parser, "ba");
@@ -117,7 +117,7 @@ namespace Hammer.Test {
         public void TestMiddle() {
             Parser parser;
             parser = Hammer.Middle(Hammer.Ch(' '), Hammer.Ch('a'), Hammer.Ch(' '));
-              CheckParseOK(parser, " a ", (System.UInt64)'a');
+              CheckParseOK(parser, " a ", 'a');
               CheckParseFail(parser, "a");
               CheckParseFail(parser, " a");
               CheckParseFail(parser, "a ");
@@ -129,21 +129,21 @@ namespace Hammer.Test {
         public void TestIn() {
             Parser parser;
             parser = Hammer.In("abc");
-              CheckParseOK(parser, "b", (System.UInt64)'b');
+              CheckParseOK(parser, "b", 'b');
               CheckParseFail(parser, "d");
         }
         [Test]
         public void TestNot_in() {
             Parser parser;
             parser = Hammer.Not_in("abc");
-              CheckParseOK(parser, "d", (System.UInt64)'d');
+              CheckParseOK(parser, "d", 'd');
               CheckParseFail(parser, "a");
         }
         [Test]
         public void TestEnd_p() {
             Parser parser;
             parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.End_p());
-              CheckParseOK(parser, "a", new object[]{ (System.UInt64)'a'});
+              CheckParseOK(parser, "a", new object[]{ 'a'});
               CheckParseFail(parser, "aa");
         }
         [Test]
@@ -156,32 +156,32 @@ namespace Hammer.Test {
         public void TestSequence() {
             Parser parser;
             parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Ch('b'));
-              CheckParseOK(parser, "ab", new object[]{ (System.UInt64)'a', (System.UInt64)'b'});
+              CheckParseOK(parser, "ab", new object[]{ 'a', 'b'});
               CheckParseFail(parser, "a");
               CheckParseFail(parser, "b");
             parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Whitespace(Hammer.Ch('b')));
-              CheckParseOK(parser, "ab", new object[]{ (System.UInt64)'a', (System.UInt64)'b'});
-              CheckParseOK(parser, "a b", new object[]{ (System.UInt64)'a', (System.UInt64)'b'});
-              CheckParseOK(parser, "a  b", new object[]{ (System.UInt64)'a', (System.UInt64)'b'});
+              CheckParseOK(parser, "ab", new object[]{ 'a', 'b'});
+              CheckParseOK(parser, "a b", new object[]{ 'a', 'b'});
+              CheckParseOK(parser, "a  b", new object[]{ 'a', 'b'});
         }
         [Test]
         public void TestChoice() {
             Parser parser;
             parser = Hammer.Choice(Hammer.Ch('a'), Hammer.Ch('b'));
-              CheckParseOK(parser, "a", (System.UInt64)'a');
-              CheckParseOK(parser, "b", (System.UInt64)'b');
-              CheckParseOK(parser, "ab", (System.UInt64)'a');
+              CheckParseOK(parser, "a", 'a');
+              CheckParseOK(parser, "b", 'b');
+              CheckParseOK(parser, "ab", 'a');
               CheckParseFail(parser, "c");
         }
         [Test]
         public void TestButnot() {
             Parser parser;
             parser = Hammer.Butnot(Hammer.Ch('a'), Hammer.Token("ab"));
-              CheckParseOK(parser, "a", (System.UInt64)'a');
+              CheckParseOK(parser, "a", 'a');
               CheckParseFail(parser, "ab");
-              CheckParseOK(parser, "aa", (System.UInt64)'a');
+              CheckParseOK(parser, "aa", 'a');
             parser = Hammer.Butnot(Hammer.Ch_range('0', '9'), Hammer.Ch('6'));
-              CheckParseOK(parser, "5", (System.UInt64)'5');
+              CheckParseOK(parser, "5", '5');
               CheckParseFail(parser, "6");
         }
         [Test]
@@ -195,8 +195,8 @@ namespace Hammer.Test {
         public void TestXor() {
             Parser parser;
             parser = Hammer.Xor(Hammer.Ch_range('0', '6'), Hammer.Ch_range('5', '9'));
-              CheckParseOK(parser, "0", (System.UInt64)'0');
-              CheckParseOK(parser, "9", (System.UInt64)'9');
+              CheckParseOK(parser, "0", '0');
+              CheckParseOK(parser, "9", '9');
               CheckParseFail(parser, "5");
               CheckParseFail(parser, "a");
         }
@@ -205,18 +205,18 @@ namespace Hammer.Test {
             Parser parser;
             parser = Hammer.Many(Hammer.Choice(Hammer.Ch('a'), Hammer.Ch('b')));
               CheckParseOK(parser, "", new object[]{ });
-              CheckParseOK(parser, "a", new object[]{ (System.UInt64)'a'});
-              CheckParseOK(parser, "b", new object[]{ (System.UInt64)'b'});
-              CheckParseOK(parser, "aabbaba", new object[]{ (System.UInt64)'a', (System.UInt64)'a', (System.UInt64)'b', (System.UInt64)'b', (System.UInt64)'a', (System.UInt64)'b', (System.UInt64)'a'});
+              CheckParseOK(parser, "a", new object[]{ 'a'});
+              CheckParseOK(parser, "b", new object[]{ 'b'});
+              CheckParseOK(parser, "aabbaba", new object[]{ 'a', 'a', 'b', 'b', 'a', 'b', 'a'});
         }
         [Test]
         public void TestMany1() {
             Parser parser;
             parser = Hammer.Many1(Hammer.Choice(Hammer.Ch('a'), Hammer.Ch('b')));
               CheckParseFail(parser, "");
-              CheckParseOK(parser, "a", new object[]{ (System.UInt64)'a'});
-              CheckParseOK(parser, "b", new object[]{ (System.UInt64)'b'});
-              CheckParseOK(parser, "aabbaba", new object[]{ (System.UInt64)'a', (System.UInt64)'a', (System.UInt64)'b', (System.UInt64)'b', (System.UInt64)'a', (System.UInt64)'b', (System.UInt64)'a'});
+              CheckParseOK(parser, "a", new object[]{ 'a'});
+              CheckParseOK(parser, "b", new object[]{ 'b'});
+              CheckParseOK(parser, "aabbaba", new object[]{ 'a', 'a', 'b', 'b', 'a', 'b', 'a'});
               CheckParseFail(parser, "daabbabadef");
         }
         [Test]
@@ -224,16 +224,16 @@ namespace Hammer.Test {
             Parser parser;
             parser = Hammer.Repeat_n(Hammer.Choice(Hammer.Ch('a'), Hammer.Ch('b')), 0x2);
               CheckParseFail(parser, "adef");
-              CheckParseOK(parser, "abdef", new object[]{ (System.UInt64)'a', (System.UInt64)'b'});
+              CheckParseOK(parser, "abdef", new object[]{ 'a', 'b'});
               CheckParseFail(parser, "dabdef");
         }
         [Test]
         public void TestOptional() {
             Parser parser;
             parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Optional(Hammer.Choice(Hammer.Ch('b'), Hammer.Ch('c'))), Hammer.Ch('d'));
-              CheckParseOK(parser, "abd", new object[]{ (System.UInt64)'a', (System.UInt64)'b', (System.UInt64)'d'});
-              CheckParseOK(parser, "acd", new object[]{ (System.UInt64)'a', (System.UInt64)'c', (System.UInt64)'d'});
-              CheckParseOK(parser, "ad", new object[]{ (System.UInt64)'a', null, (System.UInt64)'d'});
+              CheckParseOK(parser, "abd", new object[]{ 'a', 'b', 'd'});
+              CheckParseOK(parser, "acd", new object[]{ 'a', 'c', 'd'});
+              CheckParseOK(parser, "ad", new object[]{ 'a', null, 'd'});
               CheckParseFail(parser, "aed");
               CheckParseFail(parser, "ab");
               CheckParseFail(parser, "ac");
@@ -242,51 +242,51 @@ namespace Hammer.Test {
         public void TestIgnore() {
             Parser parser;
             parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Ignore(Hammer.Ch('b')), Hammer.Ch('c'));
-              CheckParseOK(parser, "abc", new object[]{ (System.UInt64)'a', (System.UInt64)'c'});
+              CheckParseOK(parser, "abc", new object[]{ 'a', 'c'});
               CheckParseFail(parser, "ac");
         }
         [Test]
         public void TestSepBy() {
             Parser parser;
             parser = Hammer.SepBy(Hammer.Choice(Hammer.Ch('1'), Hammer.Ch('2'), Hammer.Ch('3')), Hammer.Ch(','));
-              CheckParseOK(parser, "1,2,3", new object[]{ (System.UInt64)'1', (System.UInt64)'2', (System.UInt64)'3'});
-              CheckParseOK(parser, "1,3,2", new object[]{ (System.UInt64)'1', (System.UInt64)'3', (System.UInt64)'2'});
-              CheckParseOK(parser, "1,3", new object[]{ (System.UInt64)'1', (System.UInt64)'3'});
-              CheckParseOK(parser, "3", new object[]{ (System.UInt64)'3'});
+              CheckParseOK(parser, "1,2,3", new object[]{ '1', '2', '3'});
+              CheckParseOK(parser, "1,3,2", new object[]{ '1', '3', '2'});
+              CheckParseOK(parser, "1,3", new object[]{ '1', '3'});
+              CheckParseOK(parser, "3", new object[]{ '3'});
               CheckParseOK(parser, "", new object[]{ });
         }
         [Test]
         public void TestSepBy1() {
             Parser parser;
             parser = Hammer.SepBy1(Hammer.Choice(Hammer.Ch('1'), Hammer.Ch('2'), Hammer.Ch('3')), Hammer.Ch(','));
-              CheckParseOK(parser, "1,2,3", new object[]{ (System.UInt64)'1', (System.UInt64)'2', (System.UInt64)'3'});
-              CheckParseOK(parser, "1,3,2", new object[]{ (System.UInt64)'1', (System.UInt64)'3', (System.UInt64)'2'});
-              CheckParseOK(parser, "1,3", new object[]{ (System.UInt64)'1', (System.UInt64)'3'});
-              CheckParseOK(parser, "3", new object[]{ (System.UInt64)'3'});
+              CheckParseOK(parser, "1,2,3", new object[]{ '1', '2', '3'});
+              CheckParseOK(parser, "1,3,2", new object[]{ '1', '3', '2'});
+              CheckParseOK(parser, "1,3", new object[]{ '1', '3'});
+              CheckParseOK(parser, "3", new object[]{ '3'});
               CheckParseFail(parser, "");
         }
         [Test]
         public void TestAnd() {
             Parser parser;
             parser = Hammer.Sequence(Hammer.And(Hammer.Ch('0')), Hammer.Ch('0'));
-              CheckParseOK(parser, "0", new object[]{ (System.UInt64)'0'});
+              CheckParseOK(parser, "0", new object[]{ '0'});
               CheckParseFail(parser, "1");
             parser = Hammer.Sequence(Hammer.And(Hammer.Ch('0')), Hammer.Ch('1'));
               CheckParseFail(parser, "0");
               CheckParseFail(parser, "1");
             parser = Hammer.Sequence(Hammer.Ch('1'), Hammer.And(Hammer.Ch('2')));
-              CheckParseOK(parser, "12", new object[]{ (System.UInt64)'1'});
+              CheckParseOK(parser, "12", new object[]{ '1'});
               CheckParseFail(parser, "13");
         }
         [Test]
         public void TestNot() {
             Parser parser;
             parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Choice(Hammer.Token("+"), Hammer.Token("++")), Hammer.Ch('b'));
-              CheckParseOK(parser, "a+b", new object[]{ (System.UInt64)'a', new byte[]{ 0x2b}, (System.UInt64)'b'});
+              CheckParseOK(parser, "a+b", new object[]{ 'a', new byte[]{ 0x2b}, 'b'});
               CheckParseFail(parser, "a++b");
             parser = Hammer.Sequence(Hammer.Ch('a'), Hammer.Choice(Hammer.Sequence(Hammer.Token("+"), Hammer.Not(Hammer.Ch('+'))), Hammer.Token("++")), Hammer.Ch('b'));
-              CheckParseOK(parser, "a+b", new object[]{ (System.UInt64)'a', new object[]{ new byte[]{ 0x2b}}, (System.UInt64)'b'});
-              CheckParseOK(parser, "a++b", new object[]{ (System.UInt64)'a', new byte[]{ 0x2b, 0x2b}, (System.UInt64)'b'});
+              CheckParseOK(parser, "a+b", new object[]{ 'a', new object[]{ new byte[]{ 0x2b}}, 'b'});
+              CheckParseOK(parser, "a++b", new object[]{ 'a', new byte[]{ 0x2b, 0x2b}, 'b'});
         }
         [Test]
         public void TestRightrec() {
@@ -294,9 +294,9 @@ namespace Hammer.Test {
             IndirectParser sp_rr = Hammer.Indirect();
             sp_rr.Bind(Hammer.Choice(Hammer.Sequence(Hammer.Ch('a'), sp_rr), Hammer.Epsilon_p()));
             parser = sp_rr;
-              CheckParseOK(parser, "a", new object[]{ (System.UInt64)'a'});
-              CheckParseOK(parser, "aa", new object[]{ (System.UInt64)'a', new object[]{ (System.UInt64)'a'}});
-              CheckParseOK(parser, "aaa", new object[]{ (System.UInt64)'a', new object[]{ (System.UInt64)'a', new object[]{ (System.UInt64)'a'}}});
+              CheckParseOK(parser, "a", new object[]{ 'a'});
+              CheckParseOK(parser, "aa", new object[]{ 'a', new object[]{ 'a'}});
+              CheckParseOK(parser, "aaa", new object[]{ 'a', new object[]{ 'a', new object[]{ 'a'}}});
         }
         [Test]
         public void TestAmbiguous() {
@@ -308,9 +308,9 @@ namespace Hammer.Test {
             sp_p.Bind(Hammer.Ch('+'));
             sp_e.Bind(Hammer.Choice(Hammer.Sequence(sp_e, sp_p, sp_e), sp_d));
             parser = sp_e;
-              CheckParseOK(parser, "d", (System.UInt64)'d');
-              CheckParseOK(parser, "d+d", new object[]{ (System.UInt64)'d', (System.UInt64)'+', (System.UInt64)'d'});
-              CheckParseOK(parser, "d+d+d", new object[]{ new object[]{ (System.UInt64)'d', (System.UInt64)'+', (System.UInt64)'d'}, (System.UInt64)'+', (System.UInt64)'d'});
+              CheckParseOK(parser, "d", 'd');
+              CheckParseOK(parser, "d+d", new object[]{ 'd', '+', 'd'});
+              CheckParseOK(parser, "d+d+d", new object[]{ new object[]{ 'd', '+', 'd'}, '+', 'd'});
         }
     }
 }
diff --git a/src/bindings/dotnet/test/test_support.cs b/src/bindings/dotnet/test/test_support.cs
index 518a4027..98e2cdd7 100644
--- a/src/bindings/dotnet/test/test_support.cs
+++ b/src/bindings/dotnet/test/test_support.cs
@@ -80,6 +80,14 @@ namespace Hammer.Test
           System.UInt64 i = (System.UInt64)o;
           return "u0x" + i.ToString("X");
         }
+      else if (o is System.String)
+        {
+          return "\"" + o.ToString() + "\"";
+        }
+      else if (o is System.Char)
+        {
+          return "\'" + o.ToString() + "\'";
+        }
       else
         return "WAT(" + o.GetType() + ")";
     }
-- 
GitLab