[m-rev.] for review: fix an XXX: escape characters returned by deconstruct.functor/4

Julien Fischer jfischer at opturion.com
Sat Jun 9 00:05:19 AEST 2018


For review by anyone.

--------------------------------

Fix an XXX: escape characters returned by deconstruct.functor/4.

runtime/mercury_ml_expand_body.h:
     Fix an XXX: escape characters in functors.

library/rtti_implementation.m:
     Do the same for the C# and Java backends.

tests/hard_coded/deconstruct_arg.{m,exp}:
     Extend this test to cover the above.

tests/declarative_debugger/io_stream_test.exp2:
     Update this expected output: one of the I/O actions contains
     a newline character and previously the lack of a character escape
     meant that it was split across two lines.

Julien.

diff --git a/library/rtti_implementation.m b/library/rtti_implementation.m
index 0564a27..9ea5046 100644
--- a/library/rtti_implementation.m
+++ b/library/rtti_implementation.m
@@ -2814,7 +2814,11 @@ deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
      ;
          TypeCtorRep = tcr_char,
          det_dynamic_cast(Term, Char),
-        Functor = string.from_char_list(['\'', Char, '\'']),
+        ( if escape_char_functor(Char, EscapedChar) then
+            Functor = EscapedChar
+        else
+            Functor = string.from_char_list(['\'', Char, '\''])
+        ),
          Ordinal = -1,
          Arity = 0,
          Arguments = []
@@ -3010,6 +3014,18 @@ univ_named_arg(Term, NonCanon, Name, Argument) :-
          MaybeArgument),
      MaybeArgument = yes(Argument).

+:- pred escape_char_functor(character::in, string::out) is semidet.
+
+escape_char_functor('\\', "'\\\\'").
+escape_char_functor('\'', "'\\'").
+escape_char_functor('\a', "'\\a'").
+escape_char_functor('\b', "'\\b'").
+escape_char_functor('\r', "'\\r'").
+escape_char_functor('\f', "'\\f'").
+escape_char_functor('\t', "'\\t'").
+escape_char_functor('\n', "'\\n'").
+escape_char_functor('\v', "'\\v'").
+
  :- pred univ_named_arg_2(T, type_info, type_ctor_info, type_ctor_rep,
      noncanon_handling, string, maybe(univ)).
  :- mode univ_named_arg_2(in, in, in, in, in(do_not_allow), in, out) is det.
diff --git a/runtime/mercury_ml_expand_body.h b/runtime/mercury_ml_expand_body.h
index 7a1dee2..70510fc 100644
--- a/runtime/mercury_ml_expand_body.h
+++ b/runtime/mercury_ml_expand_body.h
@@ -875,14 +875,28 @@ EXPAND_FUNCTION_NAME(MR_TypeInfo type_info, MR_Word *data_word_ptr,
          case MR_TYPECTOR_REP_CHAR:
  #ifdef  EXPAND_FUNCTOR_FIELD
              {
-                // XXX Should escape characters correctly.
                  char    buf[8];
                  MR_Word data_word;
-                char    *str;
+                const char  *str_ptr;
+                char        *str;

                  data_word = *data_word_ptr;
-                sprintf(buf, "\'%c\'", (char) data_word);
-                MR_make_aligned_string_copy_saved_hp(str, buf, NULL);
+                // XXX what should we do with other non-printable characters.
+                switch (data_word) {
+                    case '\\': str_ptr = "'\\\\'"; break;
+                    case '\'': str_ptr = "'\\''"; break;
+                    case '\a': str_ptr = "'\\a'";  break;
+                    case '\b': str_ptr = "'\\b'";  break;
+                    case '\r': str_ptr = "'\\r'";  break;
+                    case '\f': str_ptr = "'\\f'";  break;
+                    case '\t': str_ptr = "'\\t'";  break;
+                    case '\n': str_ptr = "'\\n'";  break;
+                    case '\v': str_ptr = "'\\v'";  break;
+                    default:
+                        sprintf(buf, "\'%c\'", (char) data_word);
+                        str_ptr = buf;
+                }
+                MR_make_aligned_string_copy_saved_hp(str, str_ptr, NULL);
                  expand_info->EXPAND_FUNCTOR_FIELD = str;
              }
  #endif  // EXPAND_FUNCTOR_FIELD
diff --git a/tests/declarative_debugger/io_stream_test.exp2 b/tests/declarative_debugger/io_stream_test.exp2
index a5163ca..f07949b 100644
--- a/tests/declarative_debugger/io_stream_test.exp2
+++ b/tests/declarative_debugger/io_stream_test.exp2
@@ -26,8 +26,7 @@ test(stream(0, input, text, file("tabled_read_decl.data")), 1123, _, _)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '1', <<foreign(system_error, 0xXXXX)>>)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '2', <<foreign(system_error, 0xXXXX)>>)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '3', <<foreign(system_error, 0xXXXX)>>)
-read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '
-', <<foreign(system_error, 0xXXXX)>>)
+read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '\n', <<foreign(system_error, 0xXXXX)>>)
  Valid? print 1-2
  stream(0, input, text, file("tabled_read_decl.data"))
  1123
@@ -40,8 +39,7 @@ test_2(stream(0, input, text, file("tabled_read_decl.data")), 1, 1123, _, _)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '1', <<foreign(system_error, 0xXXXX)>>)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '2', <<foreign(system_error, 0xXXXX)>>)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '3', <<foreign(system_error, 0xXXXX)>>)
-read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '
-', <<foreign(system_error, 0xXXXX)>>)
+read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '\n', <<foreign(system_error, 0xXXXX)>>)
  Valid? yes
  Found incorrect contour:
  test_2(stream(0, input, text, file("tabled_read_decl.data")), 1, 1123, _, _)
@@ -49,15 +47,13 @@ test_2(stream(0, input, text, file("tabled_read_decl.data")), 1, 1123, _, _)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '1', <<foreign(system_error, 0xXXXX)>>)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '2', <<foreign(system_error, 0xXXXX)>>)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '3', <<foreign(system_error, 0xXXXX)>>)
-read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '
-', <<foreign(system_error, 0xXXXX)>>)
+read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '\n', <<foreign(system_error, 0xXXXX)>>)
  test(stream(0, input, text, file("tabled_read_decl.data")), 1123, _, _)
  4 tabled IO actions:
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '1', <<foreign(system_error, 0xXXXX)>>)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '2', <<foreign(system_error, 0xXXXX)>>)
  read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '3', <<foreign(system_error, 0xXXXX)>>)
-read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '
-', <<foreign(system_error, 0xXXXX)>>)
+read_char_code_2(<<foreign(stream, 0xXXXX)>>, ok, '\n', <<foreign(system_error, 0xXXXX)>>)
  Is this a bug? yes
        E3:     C2 EXIT pred io_stream_test.test/4-0 (det)
  mdb> c -n -S
diff --git a/tests/hard_coded/deconstruct_arg.exp b/tests/hard_coded/deconstruct_arg.exp
index 9a5af4e..bb7f081 100644
--- a/tests/hard_coded/deconstruct_arg.exp
+++ b/tests/hard_coded/deconstruct_arg.exp
@@ -124,6 +124,136 @@ deconstruct deconstruct: functor 'a' arity 0
  deconstruct limited deconstruct 3 of a
  functor 'a' arity 0 []

+deconstruct functor: '\a'/0
+deconstruct argument 0 of  doesn't exist
+deconstruct argument 1 of  doesn't exist
+deconstruct argument 2 of  doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\a' arity 0
+[]
+deconstruct limited deconstruct 3 of 
+functor '\a' arity 0 []
+
+deconstruct functor: '\b'/0
+deconstruct argument 0 of  doesn't exist
+deconstruct argument 1 of  doesn't exist
+deconstruct argument 2 of  doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\b' arity 0
+[]
+deconstruct limited deconstruct 3 of 
+functor '\b' arity 0 []
+
+deconstruct functor: '\r'/0
+deconstruct argument 0 of  doesn't exist
+deconstruct argument 1 of  doesn't exist
+deconstruct argument 2 of  doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\r' arity 0
+[]
+deconstruct limited deconstruct 3 of 
+functor '\r' arity 0 []
+
+deconstruct functor: '\f'/0
+deconstruct argument 0 of 
 doesn't exist
+deconstruct argument 1 of 
 doesn't exist
+deconstruct argument 2 of 
 doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\f' arity 0
+[]
+deconstruct limited deconstruct 3 of 
+functor '\f' arity 0 []
+
+deconstruct functor: '\t'/0
+deconstruct argument 0 of 	 doesn't exist
+deconstruct argument 1 of 	 doesn't exist
+deconstruct argument 2 of 	 doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\t' arity 0
+[]
+deconstruct limited deconstruct 3 of 
+functor '\t' arity 0 []
+
+deconstruct functor: '\n'/0
+deconstruct argument 0 of 
+ doesn't exist
+deconstruct argument 1 of 
+ doesn't exist
+deconstruct argument 2 of 
+ doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\n' arity 0
+[]
+deconstruct limited deconstruct 3 of 
+
+functor '\n' arity 0 []
+
+deconstruct functor: '\v'/0
+deconstruct argument 0 of 
 doesn't exist
+deconstruct argument 1 of 
 doesn't exist
+deconstruct argument 2 of 
 doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\v' arity 0
+[]
+deconstruct limited deconstruct 3 of 
+functor '\v' arity 0 []
+
+deconstruct functor: '\\'/0
+deconstruct argument 0 of \ doesn't exist
+deconstruct argument 1 of \ doesn't exist
+deconstruct argument 2 of \ doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\\' arity 0
+[]
+deconstruct limited deconstruct 3 of \
+functor '\\' arity 0 []
+
+deconstruct functor: '\''/0
+deconstruct argument 0 of ' doesn't exist
+deconstruct argument 1 of ' doesn't exist
+deconstruct argument 2 of ' doesn't exist
+deconstruct argument 'moo' doesn't exist
+deconstruct argument 'mooo!' doesn't exist
+deconstruct argument 'packed1' doesn't exist
+deconstruct argument 'packed2' doesn't exist
+deconstruct argument 'packed3' doesn't exist
+deconstruct deconstruct: functor '\'' arity 0
+[]
+deconstruct limited deconstruct 3 of '
+functor '\'' arity 0 []
+
  deconstruct functor: 0.12345678901234566/0
  deconstruct argument 0 of 0.12345678901234566 doesn't exist
  deconstruct argument 1 of 0.12345678901234566 doesn't exist
@@ -348,7 +478,7 @@ deconstruct deconstruct: functor newline arity 0
  deconstruct limited deconstruct 3 of '<<predicate>>'
  functor newline arity 0 []

-deconstruct functor: lambda_deconstruct_arg_m_155/1
+deconstruct functor: lambda_deconstruct_arg_m_164/1
  deconstruct argument 0 of '<<predicate>>' is [1, 2]
  deconstruct argument 1 of '<<predicate>>' doesn't exist
  deconstruct argument 2 of '<<predicate>>' doesn't exist
@@ -357,10 +487,10 @@ deconstruct argument 'mooo!' doesn't exist
  deconstruct argument 'packed1' doesn't exist
  deconstruct argument 'packed2' doesn't exist
  deconstruct argument 'packed3' doesn't exist
-deconstruct deconstruct: functor lambda_deconstruct_arg_m_155 arity 1
+deconstruct deconstruct: functor lambda_deconstruct_arg_m_164 arity 1
  [[1, 2]]
  deconstruct limited deconstruct 3 of '<<predicate>>'
-functor lambda_deconstruct_arg_m_155 arity 1 [[1, 2]]
+functor lambda_deconstruct_arg_m_164 arity 1 [[1, 2]]

  deconstruct functor: p/3
  deconstruct argument 0 of '<<predicate>>' is 1
diff --git a/tests/hard_coded/deconstruct_arg.m b/tests/hard_coded/deconstruct_arg.m
index 286e66d..dcf08cc 100644
--- a/tests/hard_coded/deconstruct_arg.m
+++ b/tests/hard_coded/deconstruct_arg.m
@@ -118,6 +118,15 @@ main(!IO) :-

      % test characters
      test_all('a', !IO),
+    test_all('\a', !IO),
+    test_all('\b', !IO),
+    test_all('\r', !IO),
+    test_all('\f', !IO),
+    test_all('\t', !IO),
+    test_all('\n', !IO),
+    test_all('\v', !IO),
+    test_all('\\', !IO),
+    test_all('\'', !IO),

      % test a float which requires 17 digits of precision
      test_all(0.12345678901234566, !IO),


More information about the reviews mailing list