[Quipu-dev] quipu/quipu: First functionality needed for string interpolation

Back to archive index

scmno****@osdn***** scmno****@osdn*****
Thu Jan 11 05:15:25 JST 2018


changeset f044f8e82b4d in quipu/quipu
details: http://hg.osdn.jp/view/quipu/quipu?cmd=changeset;node=f044f8e82b4d
user: Agustina Arzille <avarz****@riseu*****>
date: Wed Jan 10 17:15:08 2018 -0300
description: First functionality needed for string interpolation

diffstat:

 io.cpp  |  135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 io.h    |    2 +
 str.cpp |    2 +-
 str.h   |    5 +-
 4 files changed, 142 insertions(+), 2 deletions(-)

diffs (190 lines):

diff -r 96f86e4d129f -r f044f8e82b4d io.cpp
--- a/io.cpp	Wed Jan 10 04:11:35 2018 +0000
+++ b/io.cpp	Wed Jan 10 17:15:08 2018 -0300
@@ -1110,5 +1110,140 @@
   return (interp->retval);
 }
 
+// String interpolation.
+
+static int
+read_fail (interpreter *, stream&, char *, uint32_t)
+{
+  return (0);
+}
+
+static object
+read_from_cstr (interpreter *interp, const void *s, int len)
+{
+  stream instrm;
+  bvector bv;
+
+  bv.type = typecode::BVECTOR;
+  bv.nbytes = len;
+
+  instrm.rdbuf.init ((char *)s, len);
+  instrm.cookie = 0, instrm.ilock = UNBOUND;
+  instrm.bvec = bv.as_obj ();
+
+  instrm.type = typecode::STREAM;
+  instrm.pos = intobj (0);
+  instrm.flags = STRM_UTF8 | STRM_READ;
+
+  stream::xops ops;
+  ops.read = read_fail;
+
+  instrm.ops = ops;
+
+  return (read_sexpr (interp, instrm.as_obj ()));
+}
+
+static inline
+const char* xmemchr (const void *p, int ch, size_t len)
+{
+  return ((const char *)memchr (p, ch, len));
+}
+
+static bool
+sanitize_fmt (const char *p1, const char *p2)
+{
+  for (; p1 != p2; ++p1)
+    if (!isdigit (*p1) && *p1 != '.' && *p1 != '$')
+      return (false);
+
+  return (true);
+}
+
+object expand_str (interpreter *interp, object str)
+{
+  string *sp = as_str (str);
+  const char *start = (const char *)sp->data;
+  int nb = sp->nbytes;
+  const char *ptr = xmemchr (start, '%', nb);
+
+  if (!ptr)
+    qp_return (str);
+
+  stream *ns = strstream (interp, alloc_str (interp, 0), STRM_WRITE);
+  ns->write (interp, start, ptr - start);
+
+  interp->push (ns->as_obj ());
+
+  stackref args (interp, NIL);
+  object *tailp = &*args;
+
+  while (true)
+    {
+      if (ptr[1] == '%')
+        {
+          ns->nputb (interp, 2, '%');
+          const char *tp = xmemchr (ptr += 2, '%', nb -= 2);
+          if (!tp)
+            {
+              ns->write (interp, ptr, sp->nbytes - (ptr - start));
+              break;
+            }
+
+          ns->write (interp, ptr, tp - ptr);
+          nb -= tp - ptr, ptr = tp;
+          continue;
+        }
+
+      const char *p1 = xmemchr (ptr + 1, '{', ptr - start - 1);
+
+      if (!p1)
+        interp->raise2 ("arg-error", "invalid format string "
+          "(expected '{' after '%')");
+
+      nb = sp->nbytes - (int)(p1 - start);
+      const char *p2 = xmemchr (p1 + 1, '}', nb - 1);
+
+      if (!p2)
+        interp->raise2 ("arg-error", "invalid format string "
+          "(unbalanced '{}' specifiers");
+
+      object arg = read_from_cstr (interp, p1 + 1, p2 - p1);
+      *tailp = cons::make (interp, arg, *tailp);
+      tailp = &xcdr(*tailp);
+
+      if (!sanitize_fmt (ptr + 1, p1))
+        {
+          static const char ERR[] = "invalid format string: got ";
+          char buf[sizeof (ERR) * 2];
+          memcpy (buf, ERR, sizeof (ERR) - 1);
+          nb = min (sizeof (buf) - sizeof (ERR) - 1, (size_t)(p1 - ptr) - 1);
+          memcpy (buf + sizeof (ERR) - 1, ptr + 1, nb);
+          interp->raise2 ("arg-error", buf);
+        }
+
+      ns->write (interp, ptr, p1 - ptr);
+      ns->putb (interp, 'Q');
+      ptr = p2 + 1;
+
+      nb = sp->nbytes - (ptr - start);
+      ptr = xmemchr (ptr, '%', nb);
+      if (!ptr)
+        {
+          ns->write (interp, p2 + 1, nb);
+          break;
+        }
+
+      ns->write (interp, p2 + 1, ptr - p2 - 1);
+    }
+
+  if (*args == NIL)
+    // Simple string.
+    return (sstream_get (interp, ns));
+
+  *args = cons::make (interp, sstream_get (interp, ns), *args);
+  *args = cons::make (interp, intern (interp, "%fmt-str"), *args);
+  qp_return (*args);
+}
+
 QP_DECLS_END
 
diff -r 96f86e4d129f -r f044f8e82b4d io.h
--- a/io.h	Wed Jan 10 04:11:35 2018 +0000
+++ b/io.h	Wed Jan 10 17:15:08 2018 -0300
@@ -11,6 +11,8 @@
 QP_EXPORT int xwrite (interpreter *__interp,
   stream *__strm, object __obj, uint32_t *__lkcnt = 0);
 
+QP_EXPORT object expand_str (interpreter *__interp, object __str);
+
 QP_DECLS_END
 
 #endif
diff -r 96f86e4d129f -r f044f8e82b4d str.cpp
--- a/str.cpp	Wed Jan 10 04:11:35 2018 +0000
+++ b/str.cpp	Wed Jan 10 17:15:08 2018 -0300
@@ -327,7 +327,7 @@
   
   // Make up the string from the accumulated bytes.
   sstream_data *dp = (sstream_data *)strm->cookie;
-  return (string::make (interp, (const char *)dp->datap, dp->nbytes));
+  qp_return (string::make (interp, (const char *)dp->datap, dp->nbytes));
 }
 
 int write_s (interpreter *interp, stream *strm, object obj)
diff -r 96f86e4d129f -r f044f8e82b4d str.h
--- a/str.h	Wed Jan 10 04:11:35 2018 +0000
+++ b/str.h	Wed Jan 10 17:15:08 2018 -0300
@@ -19,7 +19,7 @@
   static string* alloc_raw (uint32_t __nb);
 };
 
-/* Max value for a character (as a UTF-32 codepoint). */
+// Max value for a character (as a UTF-32 codepoint).
 const uint32_t MAX_CHAR = 0x110000;
 
 #ifdef QP_ARCH_WIDE
@@ -139,6 +139,9 @@
 
 QP_EXPORT object sstream_get (interpreter *__interp, stream *__strm);
 
+QP_EXPORT object p_fmt_str (interpreter *__interp,
+  object *__argv, int __argc);
+
 QP_EXPORT const char* chobj_repr (uint32_t __ch);
 
 QP_DECLS_END




More information about the Quipu-dev mailing list
Back to archive index