public inbox for ~johnnyrichard/olang-devel@lists.sr.ht
 help / color / mirror / code / Atom feed
* [PATCH olang 0/2] Add integration tests
@ 2024-02-15 16:21 Carlos Maniero
  2024-02-15 16:21 ` [PATCH olang 1/2] tests: add munit testing framework file Carlos Maniero
  2024-02-15 16:21 ` [PATCH olang 2/2] tests: add integration test setup Carlos Maniero
  0 siblings, 2 replies; 83+ messages in thread
From: Carlos Maniero @ 2024-02-15 16:21 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Carlos Maniero

This patch is divided by two commits, the first is a copy of the
customer version of munit cloned from pipalang. The second is a
integration test setup that ensures the 0c binary is there and is
executable.

*** BLURB HERE ***

Carlos Maniero (2):
  tests: add munit testing framework file
  tests: add integration test setup

 .build.yml                     |    6 +-
 Makefile                       |   16 +
 tests/integration/Makefile     |   27 +
 tests/integration/cli_runner.c |   71 ++
 tests/integration/cli_runner.h |   27 +
 tests/integration/cli_test.c   |   39 +
 tests/integration/munit.c      | 2057 ++++++++++++++++++++++++++++++++
 tests/integration/munit.h      |  536 +++++++++
 8 files changed, 2778 insertions(+), 1 deletion(-)
 create mode 100644 tests/integration/Makefile
 create mode 100644 tests/integration/cli_runner.c
 create mode 100644 tests/integration/cli_runner.h
 create mode 100644 tests/integration/cli_test.c
 create mode 100644 tests/integration/munit.c
 create mode 100644 tests/integration/munit.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH olang 1/2] tests: add munit testing framework file
  2024-02-15 16:21 [PATCH olang 0/2] Add integration tests Carlos Maniero
@ 2024-02-15 16:21 ` Carlos Maniero
  2024-02-15 16:21 ` [PATCH olang 2/2] tests: add integration test setup Carlos Maniero
  1 sibling, 0 replies; 83+ messages in thread
From: Carlos Maniero @ 2024-02-15 16:21 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Carlos Maniero

You can learn more about it on https://nemequ.github.io/munit/

Although, this is the pipa's version:

- https://git.sr.ht/~johnnyrichard/pipac/blob/master/test/munit.c
- https://git.sr.ht/~johnnyrichard/pipac/blob/master/test/munit.h

The only change from the original project is that pipa's version
prints errors in a way vim can interprets the test file that fails.

Signed-off-by: Carlos Maniero <carlos@maniero.me>
---
 tests/integration/munit.c | 2057 +++++++++++++++++++++++++++++++++++++
 tests/integration/munit.h |  536 ++++++++++
 2 files changed, 2593 insertions(+)
 create mode 100644 tests/integration/munit.c
 create mode 100644 tests/integration/munit.h

diff --git a/tests/integration/munit.c b/tests/integration/munit.c
new file mode 100644
index 0000000..43e8e13
--- /dev/null
+++ b/tests/integration/munit.c
@@ -0,0 +1,2057 @@
+// clang-format off
+/* Copyright (c) 2013-2018 Evan Nemerson <evan@nemerson.com>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*** Configuration ***/
+
+/* This is just where the output from the test goes.  It's really just
+ * meant to let you choose stdout or stderr, but if anyone really want
+ * to direct it to a file let me know, it would be fairly easy to
+ * support. */
+#if !defined(MUNIT_OUTPUT_FILE)
+#  define MUNIT_OUTPUT_FILE stdout
+#endif
+
+/* This is a bit more useful; it tells µnit how to format the seconds in
+ * timed tests.  If your tests run for longer you might want to reduce
+ * it, and if your computer is really fast and your tests are tiny you
+ * can increase it. */
+#if !defined(MUNIT_TEST_TIME_FORMAT)
+#  define MUNIT_TEST_TIME_FORMAT "0.8f"
+#endif
+
+/* If you have long test names you might want to consider bumping
+ * this.  The result information takes 43 characters. */
+#if !defined(MUNIT_TEST_NAME_LEN)
+#  define MUNIT_TEST_NAME_LEN 37
+#endif
+
+/* If you don't like the timing information, you can disable it by
+ * defining MUNIT_DISABLE_TIMING. */
+#if !defined(MUNIT_DISABLE_TIMING)
+#  define MUNIT_ENABLE_TIMING
+#endif
+
+/*** End configuration ***/
+
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE < 200809L)
+#  undef _POSIX_C_SOURCE
+#endif
+#if !defined(_POSIX_C_SOURCE)
+#  define _POSIX_C_SOURCE 200809L
+#endif
+
+/* Solaris freaks out if you try to use a POSIX or SUS standard without
+ * the "right" C standard. */
+#if defined(_XOPEN_SOURCE)
+#  undef _XOPEN_SOURCE
+#endif
+
+#if defined(__STDC_VERSION__)
+#  if __STDC_VERSION__ >= 201112L
+#    define _XOPEN_SOURCE 700
+#  elif __STDC_VERSION__ >= 199901L
+#    define _XOPEN_SOURCE 600
+#  endif
+#endif
+
+/* Because, according to Microsoft, POSIX is deprecated.  You've got
+ * to appreciate the chutzpah. */
+#if defined(_MSC_VER) && !defined(_CRT_NONSTDC_NO_DEPRECATE)
+#  define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#  include <stdbool.h>
+#elif defined(_WIN32)
+/* https://msdn.microsoft.com/en-us/library/tf4dy80a.aspx */
+#endif
+
+#include <limits.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <setjmp.h>
+
+#if !defined(MUNIT_NO_NL_LANGINFO) && !defined(_WIN32)
+#define MUNIT_NL_LANGINFO
+#include <locale.h>
+#include <langinfo.h>
+#include <strings.h>
+#endif
+
+#if !defined(_WIN32)
+#  include <unistd.h>
+#  include <sys/types.h>
+#  include <sys/wait.h>
+#else
+#  include <windows.h>
+#  include <io.h>
+#  include <fcntl.h>
+#  if !defined(STDERR_FILENO)
+#    define STDERR_FILENO _fileno(stderr)
+#  endif
+#endif
+
+#include "munit.h"
+
+#define MUNIT_STRINGIFY(x) #x
+#define MUNIT_XSTRINGIFY(x) MUNIT_STRINGIFY(x)
+
+#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
+#  define MUNIT_THREAD_LOCAL __thread
+#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) || defined(_Thread_local)
+#  define MUNIT_THREAD_LOCAL _Thread_local
+#elif defined(_WIN32)
+#  define MUNIT_THREAD_LOCAL __declspec(thread)
+#endif
+
+/* MSVC 12.0 will emit a warning at /W4 for code like 'do { ... }
+ * while (0)', or 'do { ... } while (1)'.  I'm pretty sure nobody
+ * at Microsoft compiles with /W4. */
+#if defined(_MSC_VER) && (_MSC_VER <= 1800)
+#pragma warning(disable: 4127)
+#endif
+
+#if defined(_WIN32) || defined(__EMSCRIPTEN__)
+#  define MUNIT_NO_FORK
+#endif
+
+#if defined(__EMSCRIPTEN__)
+#  define MUNIT_NO_BUFFER
+#endif
+
+/*** Logging ***/
+
+static MunitLogLevel munit_log_level_visible = MUNIT_LOG_INFO;
+static MunitLogLevel munit_log_level_fatal = MUNIT_LOG_ERROR;
+
+#if defined(MUNIT_THREAD_LOCAL)
+static MUNIT_THREAD_LOCAL munit_bool munit_error_jmp_buf_valid = 0;
+static MUNIT_THREAD_LOCAL jmp_buf munit_error_jmp_buf;
+#endif
+
+/* At certain warning levels, mingw will trigger warnings about
+ * suggesting the format attribute, which we've explicity *not* set
+ * because it will then choke on our attempts to use the MS-specific
+ * I64 modifier for size_t (which we have to use since MSVC doesn't
+ * support the C99 z modifier). */
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
+#endif
+
+MUNIT_PRINTF(5,0)
+static void
+munit_logf_exv(MunitLogLevel level, FILE* fp, const char* filename, int line, const char* format, va_list ap) {
+  if (level < munit_log_level_visible)
+    return;
+
+  if (filename != NULL)
+    fprintf(fp, "%s:%d: ", filename, line);
+
+  switch (level) {
+    case MUNIT_LOG_DEBUG:
+      fputs("Debug", fp);
+      break;
+    case MUNIT_LOG_INFO:
+      fputs("Info", fp);
+      break;
+    case MUNIT_LOG_WARNING:
+      fputs("Warning", fp);
+      break;
+    case MUNIT_LOG_ERROR:
+      fputs("Error", fp);
+      break;
+    default:
+      munit_logf_ex(MUNIT_LOG_ERROR, filename, line, "Invalid log level (%d)", level);
+      return;
+  }
+
+  fputs(": ", fp);
+  vfprintf(fp, format, ap);
+  fputc('\n', fp);
+}
+
+MUNIT_PRINTF(3,4)
+static void
+munit_logf_internal(MunitLogLevel level, FILE* fp, const char* format, ...) {
+  va_list ap;
+
+  va_start(ap, format);
+  munit_logf_exv(level, fp, NULL, 0, format, ap);
+  va_end(ap);
+}
+
+static void
+munit_log_internal(MunitLogLevel level, FILE* fp, const char* message) {
+  munit_logf_internal(level, fp, "%s", message);
+}
+
+void
+munit_logf_ex(MunitLogLevel level, const char* filename, int line, const char* format, ...) {
+  va_list ap;
+
+  va_start(ap, format);
+  munit_logf_exv(level, stderr, filename, line, format, ap);
+  va_end(ap);
+
+  if (level >= munit_log_level_fatal) {
+#if defined(MUNIT_THREAD_LOCAL)
+    if (munit_error_jmp_buf_valid)
+      longjmp(munit_error_jmp_buf, 1);
+#endif
+    abort();
+  }
+}
+
+void
+munit_errorf_ex(const char* filename, int line, const char* format, ...) {
+  va_list ap;
+
+  va_start(ap, format);
+  munit_logf_exv(MUNIT_LOG_ERROR, stderr, filename, line, format, ap);
+  va_end(ap);
+
+#if defined(MUNIT_THREAD_LOCAL)
+  if (munit_error_jmp_buf_valid)
+    longjmp(munit_error_jmp_buf, 1);
+#endif
+  abort();
+}
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#pragma GCC diagnostic pop
+#endif
+
+#if !defined(MUNIT_STRERROR_LEN)
+#  define MUNIT_STRERROR_LEN 80
+#endif
+
+static void
+munit_log_errno(MunitLogLevel level, FILE* fp, const char* msg) {
+#if defined(MUNIT_NO_STRERROR_R) || (defined(__MINGW32__) && !defined(MINGW_HAS_SECURE_API))
+  munit_logf_internal(level, fp, "%s: %s (%d)", msg, strerror(errno), errno);
+#else
+  char munit_error_str[MUNIT_STRERROR_LEN];
+  munit_error_str[0] = '\0';
+
+#if !defined(_WIN32)
+  strerror_r(errno, munit_error_str, MUNIT_STRERROR_LEN);
+#else
+  strerror_s(munit_error_str, MUNIT_STRERROR_LEN, errno);
+#endif
+
+  munit_logf_internal(level, fp, "%s: %s (%d)", msg, munit_error_str, errno);
+#endif
+}
+
+/*** Memory allocation ***/
+
+void*
+munit_malloc_ex(const char* filename, int line, size_t size) {
+  void* ptr;
+
+  if (size == 0)
+    return NULL;
+
+  ptr = calloc(1, size);
+  if (MUNIT_UNLIKELY(ptr == NULL)) {
+    munit_logf_ex(MUNIT_LOG_ERROR, filename, line, "Failed to allocate %" MUNIT_SIZE_MODIFIER "u bytes.", size);
+  }
+
+  return ptr;
+}
+
+/*** Timer code ***/
+
+#if defined(MUNIT_ENABLE_TIMING)
+
+#define psnip_uint64_t munit_uint64_t
+#define psnip_uint32_t munit_uint32_t
+
+/* Code copied from portable-snippets
+ * <https://github.com/nemequ/portable-snippets/>.  If you need to
+ * change something, please do it there so we can keep the code in
+ * sync. */
+
+/* Clocks (v1)
+ * Portable Snippets - https://gitub.com/nemequ/portable-snippets
+ * Created by Evan Nemerson <evan@nemerson.com>
+ *
+ *   To the extent possible under law, the authors have waived all
+ *   copyright and related or neighboring rights to this code.  For
+ *   details, see the Creative Commons Zero 1.0 Universal license at
+ *   https://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+#if !defined(PSNIP_CLOCK_H)
+#define PSNIP_CLOCK_H
+
+#if !defined(psnip_uint64_t)
+#  include "../exact-int/exact-int.h"
+#endif
+
+#if !defined(PSNIP_CLOCK_STATIC_INLINE)
+#  if defined(__GNUC__)
+#    define PSNIP_CLOCK__COMPILER_ATTRIBUTES __attribute__((__unused__))
+#  else
+#    define PSNIP_CLOCK__COMPILER_ATTRIBUTES
+#  endif
+
+#  define PSNIP_CLOCK__FUNCTION PSNIP_CLOCK__COMPILER_ATTRIBUTES static
+#endif
+
+enum PsnipClockType {
+  /* This clock provides the current time, in units since 1970-01-01
+   * 00:00:00 UTC not including leap seconds.  In other words, UNIX
+   * time.  Keep in mind that this clock doesn't account for leap
+   * seconds, and can go backwards (think NTP adjustments). */
+  PSNIP_CLOCK_TYPE_WALL = 1,
+  /* The CPU time is a clock which increases only when the current
+   * process is active (i.e., it doesn't increment while blocking on
+   * I/O). */
+  PSNIP_CLOCK_TYPE_CPU = 2,
+  /* Monotonic time is always running (unlike CPU time), but it only
+     ever moves forward unless you reboot the system.  Things like NTP
+     adjustments have no effect on this clock. */
+  PSNIP_CLOCK_TYPE_MONOTONIC = 3
+};
+
+struct PsnipClockTimespec {
+  psnip_uint64_t seconds;
+  psnip_uint64_t nanoseconds;
+};
+
+/* Methods we support: */
+
+#define PSNIP_CLOCK_METHOD_CLOCK_GETTIME                   1
+#define PSNIP_CLOCK_METHOD_TIME                            2
+#define PSNIP_CLOCK_METHOD_GETTIMEOFDAY                    3
+#define PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER         4
+#define PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME              5
+#define PSNIP_CLOCK_METHOD_CLOCK                           6
+#define PSNIP_CLOCK_METHOD_GETPROCESSTIMES                 7
+#define PSNIP_CLOCK_METHOD_GETRUSAGE                       8
+#define PSNIP_CLOCK_METHOD_GETSYSTEMTIMEPRECISEASFILETIME  9
+#define PSNIP_CLOCK_METHOD_GETTICKCOUNT64                 10
+
+#include <assert.h>
+
+#if defined(HEDLEY_UNREACHABLE)
+#  define PSNIP_CLOCK_UNREACHABLE() HEDLEY_UNREACHABLE()
+#else
+#  define PSNIP_CLOCK_UNREACHABLE() assert(0)
+#endif
+
+/* Choose an implementation */
+
+/* #undef PSNIP_CLOCK_WALL_METHOD */
+/* #undef PSNIP_CLOCK_CPU_METHOD */
+/* #undef PSNIP_CLOCK_MONOTONIC_METHOD */
+
+/* We want to be able to detect the libc implementation, so we include
+   <limits.h> (<features.h> isn't available everywhere). */
+
+#if defined(__unix__) || defined(__unix) || defined(__linux__)
+#  include <limits.h>
+#  include <unistd.h>
+#endif
+
+#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
+/* These are known to work without librt.  If you know of others
+ * please let us know so we can add them. */
+#  if \
+  (defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17))) || \
+  (defined(__FreeBSD__))
+#    define PSNIP_CLOCK_HAVE_CLOCK_GETTIME
+#  elif !defined(PSNIP_CLOCK_NO_LIBRT)
+#    define PSNIP_CLOCK_HAVE_CLOCK_GETTIME
+#  endif
+#endif
+
+#if defined(_WIN32)
+#  if !defined(PSNIP_CLOCK_CPU_METHOD)
+#    define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_GETPROCESSTIMES
+#  endif
+#  if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
+#    define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
+#  endif
+#endif
+
+#if defined(__MACH__) && !defined(__gnu_hurd__)
+#  if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
+#    define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
+#  endif
+#endif
+
+#if defined(PSNIP_CLOCK_HAVE_CLOCK_GETTIME)
+#  include <time.h>
+#  if !defined(PSNIP_CLOCK_WALL_METHOD)
+#    if defined(CLOCK_REALTIME_PRECISE)
+#      define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+#      define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME_PRECISE
+#    elif !defined(__sun)
+#      define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+#      define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME
+#    endif
+#  endif
+#  if !defined(PSNIP_CLOCK_CPU_METHOD)
+#    if defined(_POSIX_CPUTIME) || defined(CLOCK_PROCESS_CPUTIME_ID)
+#      define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+#      define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_PROCESS_CPUTIME_ID
+#    elif defined(CLOCK_VIRTUAL)
+#      define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+#      define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_VIRTUAL
+#    endif
+#  endif
+#  if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
+#    if defined(CLOCK_MONOTONIC_RAW)
+#      define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+#      define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC
+#    elif defined(CLOCK_MONOTONIC_PRECISE)
+#      define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+#      define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC_PRECISE
+#    elif defined(_POSIX_MONOTONIC_CLOCK) || defined(CLOCK_MONOTONIC)
+#      define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+#      define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC
+#    endif
+#  endif
+#endif
+
+#if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)
+#  if !defined(PSNIP_CLOCK_WALL_METHOD)
+#    define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_GETTIMEOFDAY
+#  endif
+#endif
+
+#if !defined(PSNIP_CLOCK_WALL_METHOD)
+#  define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_TIME
+#endif
+
+#if !defined(PSNIP_CLOCK_CPU_METHOD)
+#  define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK
+#endif
+
+/* Primarily here for testing. */
+#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) && defined(PSNIP_CLOCK_REQUIRE_MONOTONIC)
+#  error No monotonic clock found.
+#endif
+
+/* Implementations */
+
+#if \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_CLOCK)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_CLOCK)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_TIME)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_TIME)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_TIME))
+#  include <time.h>
+#endif
+
+#if \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY))
+#  include <sys/time.h>
+#endif
+
+#if \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64))
+#  include <windows.h>
+#endif
+
+#if \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE))
+#  include <sys/resource.h>
+#  include <sys/time.h>
+#endif
+
+#if \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME))
+#  include <CoreServices/CoreServices.h>
+#  include <mach/mach.h>
+#  include <mach/mach_time.h>
+#endif
+
+/*** Implementations ***/
+
+#define PSNIP_CLOCK_NSEC_PER_SEC ((psnip_uint32_t) (1000000000ULL))
+
+#if \
+  (defined(PSNIP_CLOCK_CPU_METHOD)       && (PSNIP_CLOCK_CPU_METHOD       == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
+  (defined(PSNIP_CLOCK_WALL_METHOD)      && (PSNIP_CLOCK_WALL_METHOD      == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
+  (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME))
+PSNIP_CLOCK__FUNCTION psnip_uint32_t
+psnip_clock__clock_getres (clockid_t clk_id) {
+  struct timespec res;
+  int r;
+
+  r = clock_getres(clk_id, &res);
+  if (r != 0)
+    return 0;
+
+  return (psnip_uint32_t) (PSNIP_CLOCK_NSEC_PER_SEC / res.tv_nsec);
+}
+
+PSNIP_CLOCK__FUNCTION int
+psnip_clock__clock_gettime (clockid_t clk_id, struct PsnipClockTimespec* res) {
+  struct timespec ts;
+
+  if (clock_gettime(clk_id, &ts) != 0)
+    return -10;
+
+  res->seconds = (psnip_uint64_t) (ts.tv_sec);
+  res->nanoseconds = (psnip_uint64_t) (ts.tv_nsec);
+
+  return 0;
+}
+#endif
+
+PSNIP_CLOCK__FUNCTION psnip_uint32_t
+psnip_clock_wall_get_precision (void) {
+#if !defined(PSNIP_CLOCK_WALL_METHOD)
+  return 0;
+#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+  return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_WALL);
+#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY
+  return 1000000;
+#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+PSNIP_CLOCK__FUNCTION int
+psnip_clock_wall_get_time (struct PsnipClockTimespec* res) {
+  (void) res;
+
+#if !defined(PSNIP_CLOCK_WALL_METHOD)
+  return -2;
+#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+  return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_WALL, res);
+#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME
+  res->seconds = time(NULL);
+  res->nanoseconds = 0;
+#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY
+  struct timeval tv;
+
+  if (gettimeofday(&tv, NULL) != 0)
+    return -6;
+
+  res->seconds = tv.tv_sec;
+  res->nanoseconds = tv.tv_usec * 1000;
+#else
+  return -2;
+#endif
+
+  return 0;
+}
+
+PSNIP_CLOCK__FUNCTION psnip_uint32_t
+psnip_clock_cpu_get_precision (void) {
+#if !defined(PSNIP_CLOCK_CPU_METHOD)
+  return 0;
+#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+  return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_CPU);
+#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK
+  return CLOCKS_PER_SEC;
+#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES
+  return PSNIP_CLOCK_NSEC_PER_SEC / 100;
+#else
+  return 0;
+#endif
+}
+
+PSNIP_CLOCK__FUNCTION int
+psnip_clock_cpu_get_time (struct PsnipClockTimespec* res) {
+#if !defined(PSNIP_CLOCK_CPU_METHOD)
+  (void) res;
+  return -2;
+#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+  return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_CPU, res);
+#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK
+  clock_t t = clock();
+  if (t == ((clock_t) -1))
+    return -5;
+  res->seconds = t / CLOCKS_PER_SEC;
+  res->nanoseconds = (t % CLOCKS_PER_SEC) * (PSNIP_CLOCK_NSEC_PER_SEC / CLOCKS_PER_SEC);
+#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES
+  FILETIME CreationTime, ExitTime, KernelTime, UserTime;
+  LARGE_INTEGER date, adjust;
+
+  if (!GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime))
+    return -7;
+
+  /* http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ */
+  date.HighPart = UserTime.dwHighDateTime;
+  date.LowPart = UserTime.dwLowDateTime;
+  adjust.QuadPart = 11644473600000 * 10000;
+  date.QuadPart -= adjust.QuadPart;
+
+  res->seconds = date.QuadPart / 10000000;
+  res->nanoseconds = (date.QuadPart % 10000000) * (PSNIP_CLOCK_NSEC_PER_SEC / 100);
+#elif PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE
+  struct rusage usage;
+  if (getrusage(RUSAGE_SELF, &usage) != 0)
+    return -8;
+
+  res->seconds = usage.ru_utime.tv_sec;
+  res->nanoseconds = tv.tv_usec * 1000;
+#else
+  (void) res;
+  return -2;
+#endif
+
+  return 0;
+}
+
+PSNIP_CLOCK__FUNCTION psnip_uint32_t
+psnip_clock_monotonic_get_precision (void) {
+#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
+  return 0;
+#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+  return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC);
+#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
+  static mach_timebase_info_data_t tbi = { 0, };
+  if (tbi.denom == 0)
+    mach_timebase_info(&tbi);
+  return (psnip_uint32_t) (tbi.numer / tbi.denom);
+#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64
+  return 1000;
+#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
+  LARGE_INTEGER Frequency;
+  QueryPerformanceFrequency(&Frequency);
+  return (psnip_uint32_t) ((Frequency.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC) ? PSNIP_CLOCK_NSEC_PER_SEC : Frequency.QuadPart);
+#else
+  return 0;
+#endif
+}
+
+PSNIP_CLOCK__FUNCTION int
+psnip_clock_monotonic_get_time (struct PsnipClockTimespec* res) {
+#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
+  (void) res;
+  return -2;
+#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
+  return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC, res);
+#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
+  psnip_uint64_t nsec = mach_absolute_time();
+  static mach_timebase_info_data_t tbi = { 0, };
+  if (tbi.denom == 0)
+    mach_timebase_info(&tbi);
+  nsec *= ((psnip_uint64_t) tbi.numer) / ((psnip_uint64_t) tbi.denom);
+  res->seconds = nsec / PSNIP_CLOCK_NSEC_PER_SEC;
+  res->nanoseconds = nsec % PSNIP_CLOCK_NSEC_PER_SEC;
+#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
+  LARGE_INTEGER t, f;
+  if (QueryPerformanceCounter(&t) == 0)
+    return -12;
+
+  QueryPerformanceFrequency(&f);
+  res->seconds = t.QuadPart / f.QuadPart;
+  res->nanoseconds = t.QuadPart % f.QuadPart;
+  if (f.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC)
+    res->nanoseconds /= f.QuadPart / PSNIP_CLOCK_NSEC_PER_SEC;
+  else
+    res->nanoseconds *= PSNIP_CLOCK_NSEC_PER_SEC / f.QuadPart;
+#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64
+  const ULONGLONG msec = GetTickCount64();
+  res->seconds = msec / 1000;
+  res->nanoseconds = sec % 1000;
+#else
+  return -2;
+#endif
+
+  return 0;
+}
+
+/* Returns the number of ticks per second for the specified clock.
+ * For example, a clock with millisecond precision would return 1000,
+ * and a clock with 1 second (such as the time() function) would
+ * return 1.
+ *
+ * If the requested clock isn't available, it will return 0.
+ * Hopefully this will be rare, but if it happens to you please let us
+ * know so we can work on finding a way to support your system.
+ *
+ * Note that different clocks on the same system often have a
+ * different precisions.
+ */
+PSNIP_CLOCK__FUNCTION psnip_uint32_t
+psnip_clock_get_precision (enum PsnipClockType clock_type) {
+  switch (clock_type) {
+    case PSNIP_CLOCK_TYPE_MONOTONIC:
+      return psnip_clock_monotonic_get_precision ();
+    case PSNIP_CLOCK_TYPE_CPU:
+      return psnip_clock_cpu_get_precision ();
+    case PSNIP_CLOCK_TYPE_WALL:
+      return psnip_clock_wall_get_precision ();
+  }
+
+  PSNIP_CLOCK_UNREACHABLE();
+  return 0;
+}
+
+/* Set the provided timespec to the requested time.  Returns 0 on
+ * success, or a negative value on failure. */
+PSNIP_CLOCK__FUNCTION int
+psnip_clock_get_time (enum PsnipClockType clock_type, struct PsnipClockTimespec* res) {
+  assert(res != NULL);
+
+  switch (clock_type) {
+    case PSNIP_CLOCK_TYPE_MONOTONIC:
+      return psnip_clock_monotonic_get_time (res);
+    case PSNIP_CLOCK_TYPE_CPU:
+      return psnip_clock_cpu_get_time (res);
+    case PSNIP_CLOCK_TYPE_WALL:
+      return psnip_clock_wall_get_time (res);
+  }
+
+  return -1;
+}
+
+#endif /* !defined(PSNIP_CLOCK_H) */
+
+static psnip_uint64_t
+munit_clock_get_elapsed(struct PsnipClockTimespec* start, struct PsnipClockTimespec* end) {
+  psnip_uint64_t r = (end->seconds - start->seconds) * PSNIP_CLOCK_NSEC_PER_SEC;
+  if (end->nanoseconds < start->nanoseconds) {
+    r -= (start->nanoseconds - end->nanoseconds);
+  } else {
+    r += (end->nanoseconds - start->nanoseconds);
+  }
+  return r;
+}
+
+#else
+#  include <time.h>
+#endif /* defined(MUNIT_ENABLE_TIMING) */
+
+/*** PRNG stuff ***/
+
+/* This is (unless I screwed up, which is entirely possible) the
+ * version of PCG with 32-bit state.  It was chosen because it has a
+ * small enough state that we should reliably be able to use CAS
+ * instead of requiring a lock for thread-safety.
+ *
+ * If I did screw up, I probably will not bother changing it unless
+ * there is a significant bias.  It's really not important this be
+ * particularly strong, as long as it is fairly random it's much more
+ * important that it be reproducible, so bug reports have a better
+ * chance of being reproducible. */
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__) && !defined(__EMSCRIPTEN__) && (!defined(__GNUC_MINOR__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ > 8))
+#  define HAVE_STDATOMIC
+#elif defined(__clang__)
+#  if __has_extension(c_atomic)
+#    define HAVE_CLANG_ATOMICS
+#  endif
+#endif
+
+/* Workaround for http://llvm.org/bugs/show_bug.cgi?id=26911 */
+#if defined(__clang__) && defined(_WIN32)
+#  undef HAVE_STDATOMIC
+#  if defined(__c2__)
+#    undef HAVE_CLANG_ATOMICS
+#  endif
+#endif
+
+#if defined(_OPENMP)
+#  define ATOMIC_UINT32_T uint32_t
+#  define ATOMIC_UINT32_INIT(x) (x)
+#elif defined(HAVE_STDATOMIC)
+#  include <stdatomic.h>
+#  define ATOMIC_UINT32_T _Atomic uint32_t
+#  define ATOMIC_UINT32_INIT(x) ATOMIC_VAR_INIT(x)
+#elif defined(HAVE_CLANG_ATOMICS)
+#  define ATOMIC_UINT32_T _Atomic uint32_t
+#  define ATOMIC_UINT32_INIT(x) (x)
+#elif defined(_WIN32)
+#  define ATOMIC_UINT32_T volatile LONG
+#  define ATOMIC_UINT32_INIT(x) (x)
+#else
+#  define ATOMIC_UINT32_T volatile uint32_t
+#  define ATOMIC_UINT32_INIT(x) (x)
+#endif
+
+static ATOMIC_UINT32_T munit_rand_state = ATOMIC_UINT32_INIT(42);
+
+#if defined(_OPENMP)
+static inline void
+munit_atomic_store(ATOMIC_UINT32_T* dest, ATOMIC_UINT32_T value) {
+#pragma omp critical (munit_atomics)
+  *dest = value;
+}
+
+static inline uint32_t
+munit_atomic_load(ATOMIC_UINT32_T* src) {
+  int ret;
+#pragma omp critical (munit_atomics)
+  ret = *src;
+  return ret;
+}
+
+static inline uint32_t
+munit_atomic_cas(ATOMIC_UINT32_T* dest, ATOMIC_UINT32_T* expected, ATOMIC_UINT32_T desired) {
+  munit_bool ret;
+
+#pragma omp critical (munit_atomics)
+  {
+    if (*dest == *expected) {
+      *dest = desired;
+      ret = 1;
+    } else {
+      ret = 0;
+    }
+  }
+
+  return ret;
+}
+#elif defined(HAVE_STDATOMIC)
+#  define munit_atomic_store(dest, value)         atomic_store(dest, value)
+#  define munit_atomic_load(src)                  atomic_load(src)
+#  define munit_atomic_cas(dest, expected, value) atomic_compare_exchange_weak(dest, expected, value)
+#elif defined(HAVE_CLANG_ATOMICS)
+#  define munit_atomic_store(dest, value)         __c11_atomic_store(dest, value, __ATOMIC_SEQ_CST)
+#  define munit_atomic_load(src)                  __c11_atomic_load(src, __ATOMIC_SEQ_CST)
+#  define munit_atomic_cas(dest, expected, value) __c11_atomic_compare_exchange_weak(dest, expected, value, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#elif defined(__GNUC__) && (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
+#  define munit_atomic_store(dest, value)         __atomic_store_n(dest, value, __ATOMIC_SEQ_CST)
+#  define munit_atomic_load(src)                  __atomic_load_n(src, __ATOMIC_SEQ_CST)
+#  define munit_atomic_cas(dest, expected, value) __atomic_compare_exchange_n(dest, expected, value, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#elif defined(__GNUC__) && (__GNUC__ >= 4)
+#  define munit_atomic_store(dest,value)          do { *(dest) = (value); } while (0)
+#  define munit_atomic_load(src)                  (*(src))
+#  define munit_atomic_cas(dest, expected, value) __sync_bool_compare_and_swap(dest, *expected, value)
+#elif defined(_WIN32) /* Untested */
+#  define munit_atomic_store(dest,value)          do { *(dest) = (value); } while (0)
+#  define munit_atomic_load(src)                  (*(src))
+#  define munit_atomic_cas(dest, expected, value) InterlockedCompareExchange((dest), (value), *(expected))
+#else
+#  warning No atomic implementation, PRNG will not be thread-safe
+#  define munit_atomic_store(dest, value)         do { *(dest) = (value); } while (0)
+#  define munit_atomic_load(src)                  (*(src))
+static inline munit_bool
+munit_atomic_cas(ATOMIC_UINT32_T* dest, ATOMIC_UINT32_T* expected, ATOMIC_UINT32_T desired) {
+  if (*dest == *expected) {
+    *dest = desired;
+    return 1;
+  } else {
+    return 0;
+  }
+}
+#endif
+
+#define MUNIT_PRNG_MULTIPLIER (747796405U)
+#define MUNIT_PRNG_INCREMENT  (1729U)
+
+static munit_uint32_t
+munit_rand_next_state(munit_uint32_t state) {
+  return state * MUNIT_PRNG_MULTIPLIER + MUNIT_PRNG_INCREMENT;
+}
+
+static munit_uint32_t
+munit_rand_from_state(munit_uint32_t state) {
+  munit_uint32_t res = ((state >> ((state >> 28) + 4)) ^ state) * (277803737U);
+  res ^= res >> 22;
+  return res;
+}
+
+void
+munit_rand_seed(munit_uint32_t seed) {
+  munit_uint32_t state = munit_rand_next_state(seed + MUNIT_PRNG_INCREMENT);
+  munit_atomic_store(&munit_rand_state, state);
+}
+
+static munit_uint32_t
+munit_rand_generate_seed(void) {
+  munit_uint32_t seed, state;
+#if defined(MUNIT_ENABLE_TIMING)
+  struct PsnipClockTimespec wc = { 0, };
+
+  psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wc);
+  seed = (munit_uint32_t) wc.nanoseconds;
+#else
+  seed = (munit_uint32_t) time(NULL);
+#endif
+
+  state = munit_rand_next_state(seed + MUNIT_PRNG_INCREMENT);
+  return munit_rand_from_state(state);
+}
+
+static munit_uint32_t
+munit_rand_state_uint32(munit_uint32_t* state) {
+  const munit_uint32_t old = *state;
+  *state = munit_rand_next_state(old);
+  return munit_rand_from_state(old);
+}
+
+munit_uint32_t
+munit_rand_uint32(void) {
+  munit_uint32_t old, state;
+
+  do {
+    old = munit_atomic_load(&munit_rand_state);
+    state = munit_rand_next_state(old);
+  } while (!munit_atomic_cas(&munit_rand_state, &old, state));
+
+  return munit_rand_from_state(old);
+}
+
+static void
+munit_rand_state_memory(munit_uint32_t* state, size_t size, munit_uint8_t data[MUNIT_ARRAY_PARAM(size)]) {
+  size_t members_remaining = size / sizeof(munit_uint32_t);
+  size_t bytes_remaining = size % sizeof(munit_uint32_t);
+  munit_uint8_t* b = data;
+  munit_uint32_t rv;
+  while (members_remaining-- > 0) {
+    rv = munit_rand_state_uint32(state);
+    memcpy(b, &rv, sizeof(munit_uint32_t));
+    b += sizeof(munit_uint32_t);
+  }
+  if (bytes_remaining != 0) {
+    rv = munit_rand_state_uint32(state);
+    memcpy(b, &rv, bytes_remaining);
+  }
+}
+
+void
+munit_rand_memory(size_t size, munit_uint8_t data[MUNIT_ARRAY_PARAM(size)]) {
+  munit_uint32_t old, state;
+
+  do {
+    state = old = munit_atomic_load(&munit_rand_state);
+    munit_rand_state_memory(&state, size, data);
+  } while (!munit_atomic_cas(&munit_rand_state, &old, state));
+}
+
+static munit_uint32_t
+munit_rand_state_at_most(munit_uint32_t* state, munit_uint32_t salt, munit_uint32_t max) {
+  /* We want (UINT32_MAX + 1) % max, which in unsigned arithmetic is the same
+   * as (UINT32_MAX + 1 - max) % max = -max % max. We compute -max using not
+   * to avoid compiler warnings.
+   */
+  const munit_uint32_t min = (~max + 1U) % max;
+  munit_uint32_t x;
+
+  if (max == (~((munit_uint32_t) 0U)))
+    return munit_rand_state_uint32(state) ^ salt;
+
+  max++;
+
+  do {
+    x = munit_rand_state_uint32(state) ^ salt;
+  } while (x < min);
+
+  return x % max;
+}
+
+static munit_uint32_t
+munit_rand_at_most(munit_uint32_t salt, munit_uint32_t max) {
+  munit_uint32_t old, state;
+  munit_uint32_t retval;
+
+  do {
+    state = old = munit_atomic_load(&munit_rand_state);
+    retval = munit_rand_state_at_most(&state, salt, max);
+  } while (!munit_atomic_cas(&munit_rand_state, &old, state));
+
+  return retval;
+}
+
+int
+munit_rand_int_range(int min, int max) {
+  munit_uint64_t range = (munit_uint64_t) max - (munit_uint64_t) min;
+
+  if (min > max)
+    return munit_rand_int_range(max, min);
+
+  if (range > (~((munit_uint32_t) 0U)))
+    range = (~((munit_uint32_t) 0U));
+
+  return min + munit_rand_at_most(0, (munit_uint32_t) range);
+}
+
+double
+munit_rand_double(void) {
+  munit_uint32_t old, state;
+  double retval = 0.0;
+
+  do {
+    state = old = munit_atomic_load(&munit_rand_state);
+
+    /* See http://mumble.net/~campbell/tmp/random_real.c for how to do
+     * this right.  Patches welcome if you feel that this is too
+     * biased. */
+    retval = munit_rand_state_uint32(&state) / ((~((munit_uint32_t) 0U)) + 1.0);
+  } while (!munit_atomic_cas(&munit_rand_state, &old, state));
+
+  return retval;
+}
+
+/*** Test suite handling ***/
+
+typedef struct {
+  unsigned int successful;
+  unsigned int skipped;
+  unsigned int failed;
+  unsigned int errored;
+#if defined(MUNIT_ENABLE_TIMING)
+  munit_uint64_t cpu_clock;
+  munit_uint64_t wall_clock;
+#endif
+} MunitReport;
+
+typedef struct {
+  const char* prefix;
+  const MunitSuite* suite;
+  const char** tests;
+  munit_uint32_t seed;
+  unsigned int iterations;
+  MunitParameter* parameters;
+  munit_bool single_parameter_mode;
+  void* user_data;
+  MunitReport report;
+  munit_bool colorize;
+  munit_bool fork;
+  munit_bool show_stderr;
+  munit_bool fatal_failures;
+} MunitTestRunner;
+
+const char*
+munit_parameters_get(const MunitParameter params[], const char* key) {
+  const MunitParameter* param;
+
+  for (param = params ; param != NULL && param->name != NULL ; param++)
+    if (strcmp(param->name, key) == 0)
+      return param->value;
+  return NULL;
+}
+
+#if defined(MUNIT_ENABLE_TIMING)
+static void
+munit_print_time(FILE* fp, munit_uint64_t nanoseconds) {
+  fprintf(fp, "%" MUNIT_TEST_TIME_FORMAT, ((double) nanoseconds) / ((double) PSNIP_CLOCK_NSEC_PER_SEC));
+}
+#endif
+
+/* Add a paramter to an array of parameters. */
+static MunitResult
+munit_parameters_add(size_t* params_size, MunitParameter* params[MUNIT_ARRAY_PARAM(*params_size)], char* name, char* value) {
+  *params = realloc(*params, sizeof(MunitParameter) * (*params_size + 2));
+  if (*params == NULL)
+    return MUNIT_ERROR;
+
+  (*params)[*params_size].name = name;
+  (*params)[*params_size].value = value;
+  (*params_size)++;
+  (*params)[*params_size].name = NULL;
+  (*params)[*params_size].value = NULL;
+
+  return MUNIT_OK;
+}
+
+/* Concatenate two strings, but just return one of the components
+ * unaltered if the other is NULL or "". */
+static char*
+munit_maybe_concat(size_t* len, char* prefix, char* suffix) {
+  char* res;
+  size_t res_l;
+  const size_t prefix_l = prefix != NULL ? strlen(prefix) : 0;
+  const size_t suffix_l = suffix != NULL ? strlen(suffix) : 0;
+  if (prefix_l == 0 && suffix_l == 0) {
+    res = NULL;
+    res_l = 0;
+  } else if (prefix_l == 0 && suffix_l != 0) {
+    res = suffix;
+    res_l = suffix_l;
+  } else if (prefix_l != 0 && suffix_l == 0) {
+    res = prefix;
+    res_l = prefix_l;
+  } else {
+    res_l = prefix_l + suffix_l;
+    res = malloc(res_l + 1);
+    memcpy(res, prefix, prefix_l);
+    memcpy(res + prefix_l, suffix, suffix_l);
+    res[res_l] = 0;
+  }
+
+  if (len != NULL)
+    *len = res_l;
+
+  return res;
+}
+
+/* Possbily free a string returned by munit_maybe_concat. */
+static void
+munit_maybe_free_concat(char* s, const char* prefix, const char* suffix) {
+  if (prefix != s && suffix != s)
+    free(s);
+}
+
+/* Cheap string hash function, just used to salt the PRNG. */
+static munit_uint32_t
+munit_str_hash(const char* name) {
+  const char *p;
+  munit_uint32_t h = 5381U;
+
+  for (p = name; *p != '\0'; p++)
+    h = (h << 5) + h + *p;
+
+  return h;
+}
+
+static void
+munit_splice(int from, int to) {
+  munit_uint8_t buf[1024];
+#if !defined(_WIN32)
+  ssize_t len;
+  ssize_t bytes_written;
+  ssize_t write_res;
+#else
+  int len;
+  int bytes_written;
+  int write_res;
+#endif
+  do {
+    len = read(from, buf, sizeof(buf));
+    if (len > 0) {
+      bytes_written = 0;
+      do {
+        write_res = write(to, buf + bytes_written, len - bytes_written);
+        if (write_res < 0)
+          break;
+        bytes_written += write_res;
+      } while (bytes_written < len);
+    }
+    else
+      break;
+  } while (1);
+}
+
+/* This is the part that should be handled in the child process */
+static MunitResult
+munit_test_runner_exec(MunitTestRunner* runner, const MunitTest* test, const MunitParameter params[], MunitReport* report) {
+  unsigned int iterations = runner->iterations;
+  MunitResult result = MUNIT_FAIL;
+#if defined(MUNIT_ENABLE_TIMING)
+  struct PsnipClockTimespec wall_clock_begin = { 0, }, wall_clock_end = { 0, };
+  struct PsnipClockTimespec cpu_clock_begin = { 0, }, cpu_clock_end = { 0, };
+#endif
+  unsigned int i = 0;
+
+  if ((test->options & MUNIT_TEST_OPTION_SINGLE_ITERATION) == MUNIT_TEST_OPTION_SINGLE_ITERATION)
+    iterations = 1;
+  else if (iterations == 0)
+    iterations = runner->suite->iterations;
+
+  munit_rand_seed(runner->seed);
+
+  do {
+    void* data = (test->setup == NULL) ? runner->user_data : test->setup(params, runner->user_data);
+
+#if defined(MUNIT_ENABLE_TIMING)
+    psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wall_clock_begin);
+    psnip_clock_get_time(PSNIP_CLOCK_TYPE_CPU, &cpu_clock_begin);
+#endif
+
+    result = test->test(params, data);
+
+#if defined(MUNIT_ENABLE_TIMING)
+    psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wall_clock_end);
+    psnip_clock_get_time(PSNIP_CLOCK_TYPE_CPU, &cpu_clock_end);
+#endif
+
+    if (test->tear_down != NULL)
+      test->tear_down(data);
+
+    if (MUNIT_LIKELY(result == MUNIT_OK)) {
+      report->successful++;
+#if defined(MUNIT_ENABLE_TIMING)
+      report->wall_clock += munit_clock_get_elapsed(&wall_clock_begin, &wall_clock_end);
+      report->cpu_clock += munit_clock_get_elapsed(&cpu_clock_begin, &cpu_clock_end);
+#endif
+    } else {
+      switch ((int) result) {
+        case MUNIT_SKIP:
+          report->skipped++;
+          break;
+        case MUNIT_FAIL:
+          report->failed++;
+          break;
+        case MUNIT_ERROR:
+          report->errored++;
+          break;
+        default:
+          break;
+      }
+      break;
+    }
+  } while (++i < iterations);
+
+  return result;
+}
+
+#if defined(MUNIT_EMOTICON)
+#  define MUNIT_RESULT_STRING_OK    ":)"
+#  define MUNIT_RESULT_STRING_SKIP  ":|"
+#  define MUNIT_RESULT_STRING_FAIL  ":("
+#  define MUNIT_RESULT_STRING_ERROR ":o"
+#  define MUNIT_RESULT_STRING_TODO  ":/"
+#else
+#  define MUNIT_RESULT_STRING_OK    "OK   "
+#  define MUNIT_RESULT_STRING_SKIP  "SKIP "
+#  define MUNIT_RESULT_STRING_FAIL  "FAIL "
+#  define MUNIT_RESULT_STRING_ERROR "ERROR"
+#  define MUNIT_RESULT_STRING_TODO  "TODO "
+#endif
+
+static void
+munit_test_runner_print_color(const MunitTestRunner* runner, const char* string, char color) {
+  if (runner->colorize)
+    fprintf(MUNIT_OUTPUT_FILE, "\x1b[3%cm%s\x1b[39m", color, string);
+  else
+    fputs(string, MUNIT_OUTPUT_FILE);
+}
+
+#if !defined(MUNIT_NO_BUFFER)
+static int
+munit_replace_stderr(FILE* stderr_buf) {
+  if (stderr_buf != NULL) {
+    const int orig_stderr = dup(STDERR_FILENO);
+
+    int errfd = fileno(stderr_buf);
+    if (MUNIT_UNLIKELY(errfd == -1)) {
+      exit(EXIT_FAILURE);
+    }
+
+    dup2(errfd, STDERR_FILENO);
+
+    return orig_stderr;
+  }
+
+  return -1;
+}
+
+static void
+munit_restore_stderr(int orig_stderr) {
+  if (orig_stderr != -1) {
+    dup2(orig_stderr, STDERR_FILENO);
+    close(orig_stderr);
+  }
+}
+#endif /* !defined(MUNIT_NO_BUFFER) */
+
+/* Run a test with the specified parameters. */
+static void
+munit_test_runner_run_test_with_params(MunitTestRunner* runner, const MunitTest* test, const MunitParameter params[]) {
+  MunitResult result = MUNIT_OK;
+  MunitReport report = {
+    0, 0, 0, 0,
+#if defined(MUNIT_ENABLE_TIMING)
+    0, 0
+#endif
+  };
+  unsigned int output_l;
+  munit_bool first;
+  const MunitParameter* param;
+  FILE* stderr_buf;
+#if !defined(MUNIT_NO_FORK)
+  int pipefd[2];
+  pid_t fork_pid;
+  int orig_stderr;
+  ssize_t bytes_written = 0;
+  ssize_t write_res;
+  ssize_t bytes_read = 0;
+  ssize_t read_res;
+  int status = 0;
+  pid_t changed_pid;
+#endif
+
+  if (params != NULL) {
+    output_l = 2;
+    fputs("  ", MUNIT_OUTPUT_FILE);
+    first = 1;
+    for (param = params ; param != NULL && param->name != NULL ; param++) {
+      if (!first) {
+        fputs(", ", MUNIT_OUTPUT_FILE);
+        output_l += 2;
+      } else {
+        first = 0;
+      }
+
+      output_l += fprintf(MUNIT_OUTPUT_FILE, "%s=%s", param->name, param->value);
+    }
+    while (output_l++ < MUNIT_TEST_NAME_LEN) {
+      fputc(' ', MUNIT_OUTPUT_FILE);
+    }
+  }
+
+  fflush(MUNIT_OUTPUT_FILE);
+
+  stderr_buf = NULL;
+#if !defined(_WIN32) || defined(__MINGW32__)
+  stderr_buf = tmpfile();
+#else
+  tmpfile_s(&stderr_buf);
+#endif
+  if (stderr_buf == NULL) {
+    munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to create buffer for stderr");
+    result = MUNIT_ERROR;
+    goto print_result;
+  }
+
+#if !defined(MUNIT_NO_FORK)
+  if (runner->fork) {
+    pipefd[0] = -1;
+    pipefd[1] = -1;
+    if (pipe(pipefd) != 0) {
+      munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to create pipe");
+      result = MUNIT_ERROR;
+      goto print_result;
+    }
+
+    fork_pid = fork();
+    if (fork_pid == 0) {
+      close(pipefd[0]);
+
+      orig_stderr = munit_replace_stderr(stderr_buf);
+      munit_test_runner_exec(runner, test, params, &report);
+
+      /* Note that we don't restore stderr.  This is so we can buffer
+       * things written to stderr later on (such as by
+       * asan/tsan/ubsan, valgrind, etc.) */
+      close(orig_stderr);
+
+      do {
+        write_res = write(pipefd[1], ((munit_uint8_t*) (&report)) + bytes_written, sizeof(report) - bytes_written);
+        if (write_res < 0) {
+          if (stderr_buf != NULL) {
+            munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to write to pipe");
+          }
+          exit(EXIT_FAILURE);
+        }
+        bytes_written += write_res;
+      } while ((size_t) bytes_written < sizeof(report));
+
+      if (stderr_buf != NULL)
+        fclose(stderr_buf);
+      close(pipefd[1]);
+
+      exit(EXIT_SUCCESS);
+    } else if (fork_pid == -1) {
+      close(pipefd[0]);
+      close(pipefd[1]);
+      if (stderr_buf != NULL) {
+        munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to fork");
+      }
+      report.errored++;
+      result = MUNIT_ERROR;
+    } else {
+      close(pipefd[1]);
+      do {
+        read_res = read(pipefd[0], ((munit_uint8_t*) (&report)) + bytes_read, sizeof(report) - bytes_read);
+        if (read_res < 1)
+          break;
+        bytes_read += read_res;
+      } while (bytes_read < (ssize_t) sizeof(report));
+
+      changed_pid = waitpid(fork_pid, &status, 0);
+
+      if (MUNIT_LIKELY(changed_pid == fork_pid) && MUNIT_LIKELY(WIFEXITED(status))) {
+        if (bytes_read != sizeof(report)) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, "child exited unexpectedly with status %d", WEXITSTATUS(status));
+          report.errored++;
+        } else if (WEXITSTATUS(status) != EXIT_SUCCESS) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, "child exited with status %d", WEXITSTATUS(status));
+          report.errored++;
+        }
+      } else {
+        if (WIFSIGNALED(status)) {
+#if defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, "child killed by signal %d (%s)", WTERMSIG(status), strsignal(WTERMSIG(status)));
+#else
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, "child killed by signal %d", WTERMSIG(status));
+#endif
+        } else if (WIFSTOPPED(status)) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, "child stopped by signal %d", WSTOPSIG(status));
+        }
+        report.errored++;
+      }
+
+      close(pipefd[0]);
+      waitpid(fork_pid, NULL, 0);
+    }
+  } else
+#endif
+  {
+#if !defined(MUNIT_NO_BUFFER)
+    const volatile int orig_stderr = munit_replace_stderr(stderr_buf);
+#endif
+
+#if defined(MUNIT_THREAD_LOCAL)
+    if (MUNIT_UNLIKELY(setjmp(munit_error_jmp_buf) != 0)) {
+      result = MUNIT_FAIL;
+      report.failed++;
+    } else {
+      munit_error_jmp_buf_valid = 1;
+      result = munit_test_runner_exec(runner, test, params, &report);
+    }
+#else
+    result = munit_test_runner_exec(runner, test, params, &report);
+#endif
+
+#if !defined(MUNIT_NO_BUFFER)
+    munit_restore_stderr(orig_stderr);
+#endif
+
+    /* Here just so that the label is used on Windows and we don't get
+     * a warning */
+    goto print_result;
+  }
+
+ print_result:
+
+  fputs("[ ", MUNIT_OUTPUT_FILE);
+  if ((test->options & MUNIT_TEST_OPTION_TODO) == MUNIT_TEST_OPTION_TODO) {
+    if (report.failed != 0 || report.errored != 0 || report.skipped != 0) {
+      munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_TODO, '3');
+      result = MUNIT_OK;
+    } else {
+      munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_ERROR, '1');
+      if (MUNIT_LIKELY(stderr_buf != NULL))
+        munit_log_internal(MUNIT_LOG_ERROR, stderr_buf, "Test marked TODO, but was successful.");
+      runner->report.failed++;
+      result = MUNIT_ERROR;
+    }
+  } else if (report.failed > 0) {
+    munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_FAIL, '1');
+    runner->report.failed++;
+    result = MUNIT_FAIL;
+  } else if (report.errored > 0) {
+    munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_ERROR, '1');
+    runner->report.errored++;
+    result = MUNIT_ERROR;
+  } else if (report.skipped > 0) {
+    munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_SKIP, '3');
+    runner->report.skipped++;
+    result = MUNIT_SKIP;
+  } else if (report.successful > 1) {
+    munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_OK, '2');
+#if defined(MUNIT_ENABLE_TIMING)
+    fputs(" ] [ ", MUNIT_OUTPUT_FILE);
+    munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock / report.successful);
+    fputs(" / ", MUNIT_OUTPUT_FILE);
+    munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock / report.successful);
+    fprintf(MUNIT_OUTPUT_FILE, " CPU ]\n  %-" MUNIT_XSTRINGIFY(MUNIT_TEST_NAME_LEN) "s Total: [ ", "");
+    munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock);
+    fputs(" / ", MUNIT_OUTPUT_FILE);
+    munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock);
+    fputs(" CPU", MUNIT_OUTPUT_FILE);
+#endif
+    runner->report.successful++;
+    result = MUNIT_OK;
+  } else if (report.successful > 0) {
+    munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_OK, '2');
+#if defined(MUNIT_ENABLE_TIMING)
+    fputs(" ] [ ", MUNIT_OUTPUT_FILE);
+    munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock);
+    fputs(" / ", MUNIT_OUTPUT_FILE);
+    munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock);
+    fputs(" CPU", MUNIT_OUTPUT_FILE);
+#endif
+    runner->report.successful++;
+    result = MUNIT_OK;
+  }
+  fputs(" ]\n", MUNIT_OUTPUT_FILE);
+
+  if (stderr_buf != NULL) {
+    if (result == MUNIT_FAIL || result == MUNIT_ERROR || runner->show_stderr) {
+      fflush(MUNIT_OUTPUT_FILE);
+
+      rewind(stderr_buf);
+      munit_splice(fileno(stderr_buf), STDERR_FILENO);
+
+      fflush(stderr);
+    }
+
+    fclose(stderr_buf);
+  }
+}
+
+static void
+munit_test_runner_run_test_wild(MunitTestRunner* runner,
+                                const MunitTest* test,
+                                const char* test_name,
+                                MunitParameter* params,
+                                MunitParameter* p) {
+  const MunitParameterEnum* pe;
+  char** values;
+  MunitParameter* next;
+
+  for (pe = test->parameters ; pe != NULL && pe->name != NULL ; pe++) {
+    if (p->name == pe->name)
+      break;
+  }
+
+  if (pe == NULL)
+    return;
+
+  for (values = pe->values ; *values != NULL ; values++) {
+    next = p + 1;
+    p->value = *values;
+    if (next->name == NULL) {
+      munit_test_runner_run_test_with_params(runner, test, params);
+    } else {
+      munit_test_runner_run_test_wild(runner, test, test_name, params, next);
+    }
+    if (runner->fatal_failures && (runner->report.failed != 0 || runner->report.errored != 0))
+      break;
+  }
+}
+
+/* Run a single test, with every combination of parameters
+ * requested. */
+static void
+munit_test_runner_run_test(MunitTestRunner* runner,
+                           const MunitTest* test,
+                           const char* prefix) {
+  char* test_name = munit_maybe_concat(NULL, (char*) prefix, (char*) test->name);
+  /* The array of parameters to pass to
+   * munit_test_runner_run_test_with_params */
+  MunitParameter* params = NULL;
+  size_t params_l = 0;
+  /* Wildcard parameters are parameters which have possible values
+   * specified in the test, but no specific value was passed to the
+   * CLI.  That means we want to run the test once for every
+   * possible combination of parameter values or, if --single was
+   * passed to the CLI, a single time with a random set of
+   * parameters. */
+  MunitParameter* wild_params = NULL;
+  size_t wild_params_l = 0;
+  const MunitParameterEnum* pe;
+  const MunitParameter* cli_p;
+  munit_bool filled;
+  unsigned int possible;
+  char** vals;
+  size_t first_wild;
+  const MunitParameter* wp;
+  int pidx;
+
+  munit_rand_seed(runner->seed);
+
+  fprintf(MUNIT_OUTPUT_FILE, "%-" MUNIT_XSTRINGIFY(MUNIT_TEST_NAME_LEN) "s", test_name);
+
+  if (test->parameters == NULL) {
+    /* No parameters.  Simple, nice. */
+    munit_test_runner_run_test_with_params(runner, test, NULL);
+  } else {
+    fputc('\n', MUNIT_OUTPUT_FILE);
+
+    for (pe = test->parameters ; pe != NULL && pe->name != NULL ; pe++) {
+      /* Did we received a value for this parameter from the CLI? */
+      filled = 0;
+      for (cli_p = runner->parameters ; cli_p != NULL && cli_p->name != NULL ; cli_p++) {
+        if (strcmp(cli_p->name, pe->name) == 0) {
+          if (MUNIT_UNLIKELY(munit_parameters_add(&params_l, &params, pe->name, cli_p->value) != MUNIT_OK))
+            goto cleanup;
+          filled = 1;
+          break;
+        }
+      }
+      if (filled)
+        continue;
+
+      /* Nothing from CLI, is the enum NULL/empty?  We're not a
+       * fuzzer… */
+      if (pe->values == NULL || pe->values[0] == NULL)
+        continue;
+
+      /* If --single was passed to the CLI, choose a value from the
+       * list of possibilities randomly. */
+      if (runner->single_parameter_mode) {
+        possible = 0;
+        for (vals = pe->values ; *vals != NULL ; vals++)
+          possible++;
+        /* We want the tests to be reproducible, even if you're only
+         * running a single test, but we don't want every test with
+         * the same number of parameters to choose the same parameter
+         * number, so use the test name as a primitive salt. */
+        pidx = munit_rand_at_most(munit_str_hash(test_name), possible - 1);
+        if (MUNIT_UNLIKELY(munit_parameters_add(&params_l, &params, pe->name, pe->values[pidx]) != MUNIT_OK))
+          goto cleanup;
+      } else {
+        /* We want to try every permutation.  Put in a placeholder
+         * entry, we'll iterate through them later. */
+        if (MUNIT_UNLIKELY(munit_parameters_add(&wild_params_l, &wild_params, pe->name, NULL) != MUNIT_OK))
+          goto cleanup;
+      }
+    }
+
+    if (wild_params_l != 0) {
+      first_wild = params_l;
+      for (wp = wild_params ; wp != NULL && wp->name != NULL ; wp++) {
+        for (pe = test->parameters ; pe != NULL && pe->name != NULL && pe->values != NULL ; pe++) {
+          if (strcmp(wp->name, pe->name) == 0) {
+            if (MUNIT_UNLIKELY(munit_parameters_add(&params_l, &params, pe->name, pe->values[0]) != MUNIT_OK))
+              goto cleanup;
+          }
+        }
+      }
+
+      munit_test_runner_run_test_wild(runner, test, test_name, params, params + first_wild);
+    } else {
+      munit_test_runner_run_test_with_params(runner, test, params);
+    }
+
+  cleanup:
+    free(params);
+    free(wild_params);
+  }
+
+  munit_maybe_free_concat(test_name, prefix, test->name);
+}
+
+/* Recurse through the suite and run all the tests.  If a list of
+ * tests to run was provied on the command line, run only those
+ * tests.  */
+static void
+munit_test_runner_run_suite(MunitTestRunner* runner,
+                            const MunitSuite* suite,
+                            const char* prefix) {
+  size_t pre_l;
+  char* pre = munit_maybe_concat(&pre_l, (char*) prefix, (char*) suite->prefix);
+  const MunitTest* test;
+  const char** test_name;
+  const MunitSuite* child_suite;
+
+  /* Run the tests. */
+  for (test = suite->tests ; test != NULL && test->test != NULL ; test++) {
+    if (runner->tests != NULL) { /* Specific tests were requested on the CLI */
+      for (test_name = runner->tests ; test_name != NULL && *test_name != NULL ; test_name++) {
+        if ((pre_l == 0 || strncmp(pre, *test_name, pre_l) == 0) &&
+            strncmp(test->name, *test_name + pre_l, strlen(*test_name + pre_l)) == 0) {
+          munit_test_runner_run_test(runner, test, pre);
+          if (runner->fatal_failures && (runner->report.failed != 0 || runner->report.errored != 0))
+            goto cleanup;
+        }
+      }
+    } else { /* Run all tests */
+      munit_test_runner_run_test(runner, test, pre);
+    }
+  }
+
+  if (runner->fatal_failures && (runner->report.failed != 0 || runner->report.errored != 0))
+    goto cleanup;
+
+  /* Run any child suites. */
+  for (child_suite = suite->suites ; child_suite != NULL && child_suite->prefix != NULL ; child_suite++) {
+    munit_test_runner_run_suite(runner, child_suite, pre);
+  }
+
+ cleanup:
+
+  munit_maybe_free_concat(pre, prefix, suite->prefix);
+}
+
+static void
+munit_test_runner_run(MunitTestRunner* runner) {
+  munit_test_runner_run_suite(runner, runner->suite, NULL);
+}
+
+static void
+munit_print_help(int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)], void* user_data, const MunitArgument arguments[]) {
+  const MunitArgument* arg;
+  (void) argc;
+
+  printf("USAGE: %s [OPTIONS...] [TEST...]\n\n", argv[0]);
+  puts(" --seed SEED\n"
+       "           Value used to seed the PRNG.  Must be a 32-bit integer in decimal\n"
+       "           notation with no separators (commas, decimals, spaces, etc.), or\n"
+       "           hexidecimal prefixed by \"0x\".\n"
+       " --iterations N\n"
+       "           Run each test N times.  0 means the default number.\n"
+       " --param name value\n"
+       "           A parameter key/value pair which will be passed to any test with\n"
+       "           takes a parameter of that name.  If not provided, the test will be\n"
+       "           run once for each possible parameter value.\n"
+       " --list    Write a list of all available tests.\n"
+       " --list-params\n"
+       "           Write a list of all available tests and their possible parameters.\n"
+       " --single  Run each parameterized test in a single configuration instead of\n"
+       "           every possible combination\n"
+       " --log-visible debug|info|warning|error\n"
+       " --log-fatal debug|info|warning|error\n"
+       "           Set the level at which messages of different severities are visible,\n"
+       "           or cause the test to terminate.\n"
+#if !defined(MUNIT_NO_FORK)
+       " --no-fork Do not execute tests in a child process.  If this option is supplied\n"
+       "           and a test crashes (including by failing an assertion), no further\n"
+       "           tests will be performed.\n"
+#endif
+       " --fatal-failures\n"
+       "           Stop executing tests as soon as a failure is found.\n"
+       " --show-stderr\n"
+       "           Show data written to stderr by the tests, even if the test succeeds.\n"
+       " --color auto|always|never\n"
+       "           Colorize (or don't) the output.\n"
+     /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
+       " --help    Print this help message and exit.\n");
+#if defined(MUNIT_NL_LANGINFO)
+  setlocale(LC_ALL, "");
+  fputs((strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) ? "µnit" : "munit", stdout);
+#else
+  puts("munit");
+#endif
+  printf(" %d.%d.%d\n"
+         "Full documentation at: https://nemequ.github.io/munit/\n",
+         (MUNIT_CURRENT_VERSION >> 16) & 0xff,
+         (MUNIT_CURRENT_VERSION >> 8) & 0xff,
+         (MUNIT_CURRENT_VERSION >> 0) & 0xff);
+  for (arg = arguments ; arg != NULL && arg->name != NULL ; arg++)
+    arg->write_help(arg, user_data);
+}
+
+static const MunitArgument*
+munit_arguments_find(const MunitArgument arguments[], const char* name) {
+  const MunitArgument* arg;
+
+  for (arg = arguments ; arg != NULL && arg->name != NULL ; arg++)
+    if (strcmp(arg->name, name) == 0)
+      return arg;
+
+  return NULL;
+}
+
+static void
+munit_suite_list_tests(const MunitSuite* suite, munit_bool show_params, const char* prefix) {
+  size_t pre_l;
+  char* pre = munit_maybe_concat(&pre_l, (char*) prefix, (char*) suite->prefix);
+  const MunitTest* test;
+  const MunitParameterEnum* params;
+  munit_bool first;
+  char** val;
+  const MunitSuite* child_suite;
+
+  for (test = suite->tests ;
+       test != NULL && test->name != NULL ;
+       test++) {
+    if (pre != NULL)
+      fputs(pre, stdout);
+    puts(test->name);
+
+    if (show_params) {
+      for (params = test->parameters ;
+           params != NULL && params->name != NULL ;
+           params++) {
+        fprintf(stdout, " - %s: ", params->name);
+        if (params->values == NULL) {
+          puts("Any");
+        } else {
+          first = 1;
+          for (val = params->values ;
+               *val != NULL ;
+               val++ ) {
+            if(!first) {
+              fputs(", ", stdout);
+            } else {
+              first = 0;
+            }
+            fputs(*val, stdout);
+          }
+          putc('\n', stdout);
+        }
+      }
+    }
+  }
+
+  for (child_suite = suite->suites ; child_suite != NULL && child_suite->prefix != NULL ; child_suite++) {
+    munit_suite_list_tests(child_suite, show_params, pre);
+  }
+
+  munit_maybe_free_concat(pre, prefix, suite->prefix);
+}
+
+static munit_bool
+munit_stream_supports_ansi(FILE *stream) {
+#if !defined(_WIN32)
+  return isatty(fileno(stream));
+#else
+
+#if !defined(__MINGW32__)
+  size_t ansicon_size = 0;
+#endif
+
+  if (isatty(fileno(stream))) {
+#if !defined(__MINGW32__)
+    getenv_s(&ansicon_size, NULL, 0, "ANSICON");
+    return ansicon_size != 0;
+#else
+    return getenv("ANSICON") != NULL;
+#endif
+  }
+  return 0;
+#endif
+}
+
+int
+munit_suite_main_custom(const MunitSuite* suite, void* user_data,
+                        int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)],
+                        const MunitArgument arguments[]) {
+  int result = EXIT_FAILURE;
+  MunitTestRunner runner;
+  size_t parameters_size = 0;
+  size_t tests_size = 0;
+  int arg;
+
+  char* envptr;
+  unsigned long ts;
+  char* endptr;
+  unsigned long long iterations;
+  MunitLogLevel level;
+  const MunitArgument* argument;
+  const char** runner_tests;
+  unsigned int tests_run;
+  unsigned int tests_total;
+
+  runner.prefix = NULL;
+  runner.suite = NULL;
+  runner.tests = NULL;
+  runner.seed = 0;
+  runner.iterations = 0;
+  runner.parameters = NULL;
+  runner.single_parameter_mode = 0;
+  runner.user_data = NULL;
+
+  runner.report.successful = 0;
+  runner.report.skipped = 0;
+  runner.report.failed = 0;
+  runner.report.errored = 0;
+#if defined(MUNIT_ENABLE_TIMING)
+  runner.report.cpu_clock = 0;
+  runner.report.wall_clock = 0;
+#endif
+
+  runner.colorize = 0;
+#if !defined(_WIN32)
+  runner.fork = 1;
+#else
+  runner.fork = 0;
+#endif
+  runner.show_stderr = 0;
+  runner.fatal_failures = 0;
+  runner.suite = suite;
+  runner.user_data = user_data;
+  runner.seed = munit_rand_generate_seed();
+  runner.colorize = munit_stream_supports_ansi(MUNIT_OUTPUT_FILE);
+
+  for (arg = 1 ; arg < argc ; arg++) {
+    if (strncmp("--", argv[arg], 2) == 0) {
+      if (strcmp("seed", argv[arg] + 2) == 0) {
+        if (arg + 1 >= argc) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "%s requires an argument", argv[arg]);
+          goto cleanup;
+        }
+
+        envptr = argv[arg + 1];
+        ts = strtoul(argv[arg + 1], &envptr, 0);
+        if (*envptr != '\0' || ts > (~((munit_uint32_t) 0U))) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "invalid value ('%s') passed to %s", argv[arg + 1], argv[arg]);
+          goto cleanup;
+        }
+        runner.seed = (munit_uint32_t) ts;
+
+        arg++;
+      } else if (strcmp("iterations", argv[arg] + 2) == 0) {
+        if (arg + 1 >= argc) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "%s requires an argument", argv[arg]);
+          goto cleanup;
+        }
+
+        endptr = argv[arg + 1];
+        iterations = strtoul(argv[arg + 1], &endptr, 0);
+        if (*endptr != '\0' || iterations > UINT_MAX) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "invalid value ('%s') passed to %s", argv[arg + 1], argv[arg]);
+          goto cleanup;
+        }
+
+        runner.iterations = (unsigned int) iterations;
+
+        arg++;
+      } else if (strcmp("param", argv[arg] + 2) == 0) {
+        if (arg + 2 >= argc) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "%s requires two arguments", argv[arg]);
+          goto cleanup;
+        }
+
+        runner.parameters = realloc(runner.parameters, sizeof(MunitParameter) * (parameters_size + 2));
+        if (runner.parameters == NULL) {
+          munit_log_internal(MUNIT_LOG_ERROR, stderr, "failed to allocate memory");
+          goto cleanup;
+        }
+        runner.parameters[parameters_size].name = (char*) argv[arg + 1];
+        runner.parameters[parameters_size].value = (char*) argv[arg + 2];
+        parameters_size++;
+        runner.parameters[parameters_size].name = NULL;
+        runner.parameters[parameters_size].value = NULL;
+        arg += 2;
+      } else if (strcmp("color", argv[arg] + 2) == 0) {
+        if (arg + 1 >= argc) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "%s requires an argument", argv[arg]);
+          goto cleanup;
+        }
+
+        if (strcmp(argv[arg + 1], "always") == 0)
+          runner.colorize = 1;
+        else if (strcmp(argv[arg + 1], "never") == 0)
+          runner.colorize = 0;
+        else if (strcmp(argv[arg + 1], "auto") == 0)
+          runner.colorize = munit_stream_supports_ansi(MUNIT_OUTPUT_FILE);
+        else {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "invalid value ('%s') passed to %s", argv[arg + 1], argv[arg]);
+          goto cleanup;
+        }
+
+        arg++;
+      } else if (strcmp("help", argv[arg] + 2) == 0) {
+        munit_print_help(argc, argv, user_data, arguments);
+        result = EXIT_SUCCESS;
+        goto cleanup;
+      } else if (strcmp("single", argv[arg] + 2) == 0) {
+        runner.single_parameter_mode = 1;
+      } else if (strcmp("show-stderr", argv[arg] + 2) == 0) {
+        runner.show_stderr = 1;
+#if !defined(_WIN32)
+      } else if (strcmp("no-fork", argv[arg] + 2) == 0) {
+        runner.fork = 0;
+#endif
+      } else if (strcmp("fatal-failures", argv[arg] + 2) == 0) {
+        runner.fatal_failures = 1;
+      } else if (strcmp("log-visible", argv[arg] + 2) == 0 ||
+                 strcmp("log-fatal", argv[arg] + 2) == 0) {
+        if (arg + 1 >= argc) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "%s requires an argument", argv[arg]);
+          goto cleanup;
+        }
+
+        if (strcmp(argv[arg + 1], "debug") == 0)
+          level = MUNIT_LOG_DEBUG;
+        else if (strcmp(argv[arg + 1], "info") == 0)
+          level = MUNIT_LOG_INFO;
+        else if (strcmp(argv[arg + 1], "warning") == 0)
+          level = MUNIT_LOG_WARNING;
+        else if (strcmp(argv[arg + 1], "error") == 0)
+          level = MUNIT_LOG_ERROR;
+        else {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "invalid value ('%s') passed to %s", argv[arg + 1], argv[arg]);
+          goto cleanup;
+        }
+
+        if (strcmp("log-visible", argv[arg] + 2) == 0)
+          munit_log_level_visible = level;
+        else
+          munit_log_level_fatal = level;
+
+        arg++;
+      } else if (strcmp("list", argv[arg] + 2) == 0) {
+        munit_suite_list_tests(suite, 0, NULL);
+        result = EXIT_SUCCESS;
+        goto cleanup;
+      } else if (strcmp("list-params", argv[arg] + 2) == 0) {
+        munit_suite_list_tests(suite, 1, NULL);
+        result = EXIT_SUCCESS;
+        goto cleanup;
+      } else {
+        argument = munit_arguments_find(arguments, argv[arg] + 2);
+        if (argument == NULL) {
+          munit_logf_internal(MUNIT_LOG_ERROR, stderr, "unknown argument ('%s')", argv[arg]);
+          goto cleanup;
+        }
+
+        if (!argument->parse_argument(suite, user_data, &arg, argc, argv))
+          goto cleanup;
+      }
+    } else {
+      runner_tests = realloc((void*) runner.tests, sizeof(char*) * (tests_size + 2));
+      if (runner_tests == NULL) {
+        munit_log_internal(MUNIT_LOG_ERROR, stderr, "failed to allocate memory");
+        goto cleanup;
+      }
+      runner.tests = runner_tests;
+      runner.tests[tests_size++] = argv[arg];
+      runner.tests[tests_size] = NULL;
+    }
+  }
+
+  fflush(stderr);
+  fprintf(MUNIT_OUTPUT_FILE, "Running test suite with seed 0x%08" PRIx32 "...\n", runner.seed);
+
+  munit_test_runner_run(&runner);
+
+  tests_run = runner.report.successful + runner.report.failed + runner.report.errored;
+  tests_total = tests_run + runner.report.skipped;
+  if (tests_run == 0) {
+    fprintf(stderr, "No tests run, %d (100%%) skipped.\n", runner.report.skipped);
+  } else {
+    fprintf(MUNIT_OUTPUT_FILE, "%d of %d (%0.0f%%) tests successful, %d (%0.0f%%) test skipped.\n",
+            runner.report.successful, tests_run,
+            (((double) runner.report.successful) / ((double) tests_run)) * 100.0,
+            runner.report.skipped,
+            (((double) runner.report.skipped) / ((double) tests_total)) * 100.0);
+  }
+
+  if (runner.report.failed == 0 && runner.report.errored == 0) {
+    result = EXIT_SUCCESS;
+  }
+
+ cleanup:
+  free(runner.parameters);
+  free((void*) runner.tests);
+
+  return result;
+}
+
+int
+munit_suite_main(const MunitSuite* suite, void* user_data,
+                 int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
+  return munit_suite_main_custom(suite, user_data, argc, argv, NULL);
+}
diff --git a/tests/integration/munit.h b/tests/integration/munit.h
new file mode 100644
index 0000000..c614c78
--- /dev/null
+++ b/tests/integration/munit.h
@@ -0,0 +1,536 @@
+// clang-format off
+/* µnit Testing Framework
+ * Copyright (c) 2013-2017 Evan Nemerson <evan@nemerson.com>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if !defined(MUNIT_H)
+#define MUNIT_H
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define MUNIT_VERSION(major, minor, revision) \
+  (((major) << 16) | ((minor) << 8) | (revision))
+
+#define MUNIT_CURRENT_VERSION MUNIT_VERSION(0, 4, 1)
+
+#if defined(_MSC_VER) && (_MSC_VER < 1600)
+#  define munit_int8_t   __int8
+#  define munit_uint8_t  unsigned __int8
+#  define munit_int16_t  __int16
+#  define munit_uint16_t unsigned __int16
+#  define munit_int32_t  __int32
+#  define munit_uint32_t unsigned __int32
+#  define munit_int64_t  __int64
+#  define munit_uint64_t unsigned __int64
+#else
+#  include <stdint.h>
+#  define munit_int8_t   int8_t
+#  define munit_uint8_t  uint8_t
+#  define munit_int16_t  int16_t
+#  define munit_uint16_t uint16_t
+#  define munit_int32_t  int32_t
+#  define munit_uint32_t uint32_t
+#  define munit_int64_t  int64_t
+#  define munit_uint64_t uint64_t
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER < 1800)
+#  if !defined(PRIi8)
+#    define PRIi8 "i"
+#  endif
+#  if !defined(PRIi16)
+#    define PRIi16 "i"
+#  endif
+#  if !defined(PRIi32)
+#    define PRIi32 "i"
+#  endif
+#  if !defined(PRIi64)
+#    define PRIi64 "I64i"
+#  endif
+#  if !defined(PRId8)
+#    define PRId8 "d"
+#  endif
+#  if !defined(PRId16)
+#    define PRId16 "d"
+#  endif
+#  if !defined(PRId32)
+#    define PRId32 "d"
+#  endif
+#  if !defined(PRId64)
+#    define PRId64 "I64d"
+#  endif
+#  if !defined(PRIx8)
+#    define PRIx8 "x"
+#  endif
+#  if !defined(PRIx16)
+#    define PRIx16 "x"
+#  endif
+#  if !defined(PRIx32)
+#    define PRIx32 "x"
+#  endif
+#  if !defined(PRIx64)
+#    define PRIx64 "I64x"
+#  endif
+#  if !defined(PRIu8)
+#    define PRIu8 "u"
+#  endif
+#  if !defined(PRIu16)
+#    define PRIu16 "u"
+#  endif
+#  if !defined(PRIu32)
+#    define PRIu32 "u"
+#  endif
+#  if !defined(PRIu64)
+#    define PRIu64 "I64u"
+#  endif
+#else
+#  include <inttypes.h>
+#endif
+
+#if !defined(munit_bool)
+#  if defined(bool)
+#    define munit_bool bool
+#  elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#    define munit_bool _Bool
+#  else
+#    define munit_bool int
+#  endif
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(__GNUC__)
+#  define MUNIT_LIKELY(expr) (__builtin_expect ((expr), 1))
+#  define MUNIT_UNLIKELY(expr) (__builtin_expect ((expr), 0))
+#  define MUNIT_UNUSED __attribute__((__unused__))
+#else
+#  define MUNIT_LIKELY(expr) (expr)
+#  define MUNIT_UNLIKELY(expr) (expr)
+#  define MUNIT_UNUSED
+#endif
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__PGI)
+#  define MUNIT_ARRAY_PARAM(name) name
+#else
+#  define MUNIT_ARRAY_PARAM(name)
+#endif
+
+#if !defined(_WIN32)
+#  define MUNIT_SIZE_MODIFIER "z"
+#  define MUNIT_CHAR_MODIFIER "hh"
+#  define MUNIT_SHORT_MODIFIER "h"
+#else
+#  if defined(_M_X64) || defined(__amd64__)
+#    define MUNIT_SIZE_MODIFIER "I64"
+#  else
+#    define MUNIT_SIZE_MODIFIER ""
+#  endif
+#  define MUNIT_CHAR_MODIFIER ""
+#  define MUNIT_SHORT_MODIFIER ""
+#endif
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#  define MUNIT_NO_RETURN _Noreturn
+#elif defined(__GNUC__)
+#  define MUNIT_NO_RETURN __attribute__((__noreturn__))
+#elif defined(_MSC_VER)
+#  define MUNIT_NO_RETURN __declspec(noreturn)
+#else
+#  define MUNIT_NO_RETURN
+#endif
+
+#if defined(_MSC_VER) &&  (_MSC_VER >= 1500)
+#  define MUNIT_PUSH_DISABLE_MSVC_C4127_ __pragma(warning(push)) __pragma(warning(disable:4127))
+#  define MUNIT_POP_DISABLE_MSVC_C4127_ __pragma(warning(pop))
+#else
+#  define MUNIT_PUSH_DISABLE_MSVC_C4127_
+#  define MUNIT_POP_DISABLE_MSVC_C4127_
+#endif
+
+typedef enum {
+  MUNIT_LOG_DEBUG,
+  MUNIT_LOG_INFO,
+  MUNIT_LOG_WARNING,
+  MUNIT_LOG_ERROR
+} MunitLogLevel;
+
+#if defined(__GNUC__) && !defined(__MINGW32__)
+#  define MUNIT_PRINTF(string_index, first_to_check) __attribute__((format (printf, string_index, first_to_check)))
+#else
+#  define MUNIT_PRINTF(string_index, first_to_check)
+#endif
+
+MUNIT_PRINTF(4, 5)
+void munit_logf_ex(MunitLogLevel level, const char* filename, int line, const char* format, ...);
+
+#define munit_logf(level, format, ...) \
+  munit_logf_ex(level, __FILE__, __LINE__, format, __VA_ARGS__)
+
+#define munit_log(level, msg) \
+  munit_logf(level, "%s", msg)
+
+MUNIT_NO_RETURN
+MUNIT_PRINTF(3, 4)
+void munit_errorf_ex(const char* filename, int line, const char* format, ...);
+
+#define munit_errorf(format, ...) \
+  munit_errorf_ex(__FILE__, __LINE__, format, __VA_ARGS__)
+
+#define munit_error(msg) \
+  munit_errorf("%s", msg)
+
+#define munit_assert(expr) \
+  do { \
+    if (!MUNIT_LIKELY(expr)) { \
+      munit_error("assertion failed: " #expr); \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#define munit_assert_true(expr) \
+  do { \
+    if (!MUNIT_LIKELY(expr)) { \
+      munit_error("assertion failed: " #expr " is not true"); \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#define munit_assert_false(expr) \
+  do { \
+    if (!MUNIT_LIKELY(!(expr))) { \
+      munit_error("assertion failed: " #expr " is not false"); \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#define munit_assert_type_full(prefix, suffix, T, fmt, a, op, b)   \
+  do { \
+    T munit_tmp_a_ = (a); \
+    T munit_tmp_b_ = (b); \
+    if (!(munit_tmp_a_ op munit_tmp_b_)) {                               \
+      munit_errorf("assertion failed: %s %s %s (" prefix "%" fmt suffix " %s " prefix "%" fmt suffix ")", \
+                   #a, #op, #b, munit_tmp_a_, #op, munit_tmp_b_); \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#define munit_assert_type(T, fmt, a, op, b) \
+  munit_assert_type_full("", "", T, fmt, a, op, b)
+
+#define munit_assert_char(a, op, b) \
+  munit_assert_type_full("'\\x", "'", char, "02" MUNIT_CHAR_MODIFIER "x", a, op, b)
+#define munit_assert_uchar(a, op, b) \
+  munit_assert_type_full("'\\x", "'", unsigned char, "02" MUNIT_CHAR_MODIFIER "x", a, op, b)
+#define munit_assert_short(a, op, b) \
+  munit_assert_type(short, MUNIT_SHORT_MODIFIER "d", a, op, b)
+#define munit_assert_ushort(a, op, b) \
+  munit_assert_type(unsigned short, MUNIT_SHORT_MODIFIER "u", a, op, b)
+#define munit_assert_int(a, op, b) \
+  munit_assert_type(int, "d", a, op, b)
+#define munit_assert_uint(a, op, b) \
+  munit_assert_type(unsigned int, "u", a, op, b)
+#define munit_assert_long(a, op, b) \
+  munit_assert_type(long int, "ld", a, op, b)
+#define munit_assert_ulong(a, op, b) \
+  munit_assert_type(unsigned long int, "lu", a, op, b)
+#define munit_assert_llong(a, op, b) \
+  munit_assert_type(long long int, "lld", a, op, b)
+#define munit_assert_ullong(a, op, b) \
+  munit_assert_type(unsigned long long int, "llu", a, op, b)
+
+#define munit_assert_size(a, op, b) \
+  munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", a, op, b)
+
+#define munit_assert_float(a, op, b) \
+  munit_assert_type(float, "f", a, op, b)
+#define munit_assert_double(a, op, b) \
+  munit_assert_type(double, "g", a, op, b)
+#define munit_assert_ptr(a, op, b) \
+  munit_assert_type(const void*, "p", a, op, b)
+
+#define munit_assert_int8(a, op, b)             \
+  munit_assert_type(munit_int8_t, PRIi8, a, op, b)
+#define munit_assert_uint8(a, op, b) \
+  munit_assert_type(munit_uint8_t, PRIu8, a, op, b)
+#define munit_assert_int16(a, op, b) \
+  munit_assert_type(munit_int16_t, PRIi16, a, op, b)
+#define munit_assert_uint16(a, op, b) \
+  munit_assert_type(munit_uint16_t, PRIu16, a, op, b)
+#define munit_assert_int32(a, op, b) \
+  munit_assert_type(munit_int32_t, PRIi32, a, op, b)
+#define munit_assert_uint32(a, op, b) \
+  munit_assert_type(munit_uint32_t, PRIu32, a, op, b)
+#define munit_assert_int64(a, op, b) \
+  munit_assert_type(munit_int64_t, PRIi64, a, op, b)
+#define munit_assert_uint64(a, op, b) \
+  munit_assert_type(munit_uint64_t, PRIu64, a, op, b)
+
+#define munit_assert_double_equal(a, b, precision) \
+  do { \
+    const double munit_tmp_a_ = (a); \
+    const double munit_tmp_b_ = (b); \
+    const double munit_tmp_diff_ = ((munit_tmp_a_ - munit_tmp_b_) < 0) ? \
+      -(munit_tmp_a_ - munit_tmp_b_) : \
+      (munit_tmp_a_ - munit_tmp_b_); \
+    if (MUNIT_UNLIKELY(munit_tmp_diff_ > 1e-##precision)) { \
+      munit_errorf("assertion failed: %s == %s (%0." #precision "g == %0." #precision "g)", \
+		   #a, #b, munit_tmp_a_, munit_tmp_b_); \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#include <string.h>
+#define munit_assert_string_equal(a, b) \
+  do { \
+    const char* munit_tmp_a_ = a; \
+    const char* munit_tmp_b_ = b; \
+    if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) != 0)) { \
+      munit_errorf("assertion failed: string %s == %s (\"%s\" == \"%s\")", \
+                   #a, #b, munit_tmp_a_, munit_tmp_b_); \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#define munit_assert_string_not_equal(a, b) \
+  do { \
+    const char* munit_tmp_a_ = a; \
+    const char* munit_tmp_b_ = b; \
+    if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) == 0)) { \
+      munit_errorf("assertion failed: string %s != %s (\"%s\" == \"%s\")", \
+                   #a, #b, munit_tmp_a_, munit_tmp_b_); \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#define munit_assert_memory_equal(size, a, b) \
+  do { \
+    const unsigned char* munit_tmp_a_ = (const unsigned char*) (a); \
+    const unsigned char* munit_tmp_b_ = (const unsigned char*) (b); \
+    const size_t munit_tmp_size_ = (size); \
+    if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) != 0) { \
+      size_t munit_tmp_pos_; \
+      for (munit_tmp_pos_ = 0 ; munit_tmp_pos_ < munit_tmp_size_ ; munit_tmp_pos_++) { \
+        if (munit_tmp_a_[munit_tmp_pos_] != munit_tmp_b_[munit_tmp_pos_]) { \
+          munit_errorf("assertion failed: memory %s == %s, at offset %" MUNIT_SIZE_MODIFIER "u", \
+                       #a, #b, munit_tmp_pos_); \
+          break; \
+        } \
+      } \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#define munit_assert_memory_not_equal(size, a, b) \
+  do { \
+    const unsigned char* munit_tmp_a_ = (const unsigned char*) (a); \
+    const unsigned char* munit_tmp_b_ = (const unsigned char*) (b); \
+    const size_t munit_tmp_size_ = (size); \
+    if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) == 0) { \
+      munit_errorf("assertion failed: memory %s != %s (%zu bytes)", \
+                   #a, #b, munit_tmp_size_); \
+    } \
+    MUNIT_PUSH_DISABLE_MSVC_C4127_ \
+  } while (0) \
+  MUNIT_POP_DISABLE_MSVC_C4127_
+
+#define munit_assert_ptr_equal(a, b) \
+  munit_assert_ptr(a, ==, b)
+#define munit_assert_ptr_not_equal(a, b) \
+  munit_assert_ptr(a, !=, b)
+#define munit_assert_null(ptr) \
+  munit_assert_ptr(ptr, ==, NULL)
+#define munit_assert_not_null(ptr) \
+  munit_assert_ptr(ptr, !=, NULL)
+#define munit_assert_ptr_null(ptr) \
+  munit_assert_ptr(ptr, ==, NULL)
+#define munit_assert_ptr_not_null(ptr) \
+  munit_assert_ptr(ptr, !=, NULL)
+
+/*** Memory allocation ***/
+
+void* munit_malloc_ex(const char* filename, int line, size_t size);
+
+#define munit_malloc(size) \
+  munit_malloc_ex(__FILE__, __LINE__, (size))
+
+#define munit_new(type) \
+  ((type*) munit_malloc(sizeof(type)))
+
+#define munit_calloc(nmemb, size) \
+  munit_malloc((nmemb) * (size))
+
+#define munit_newa(type, nmemb) \
+  ((type*) munit_calloc((nmemb), sizeof(type)))
+
+/*** Random number generation ***/
+
+void munit_rand_seed(munit_uint32_t seed);
+munit_uint32_t munit_rand_uint32(void);
+int munit_rand_int_range(int min, int max);
+double munit_rand_double(void);
+void munit_rand_memory(size_t size, munit_uint8_t buffer[MUNIT_ARRAY_PARAM(size)]);
+
+/*** Tests and Suites ***/
+
+typedef enum {
+  /* Test successful */
+  MUNIT_OK,
+  /* Test failed */
+  MUNIT_FAIL,
+  /* Test was skipped */
+  MUNIT_SKIP,
+  /* Test failed due to circumstances not intended to be tested
+   * (things like network errors, invalid parameter value, failure to
+   * allocate memory in the test harness, etc.). */
+  MUNIT_ERROR
+} MunitResult;
+
+typedef struct {
+  char*  name;
+  char** values;
+} MunitParameterEnum;
+
+typedef struct {
+  char* name;
+  char* value;
+} MunitParameter;
+
+const char* munit_parameters_get(const MunitParameter params[], const char* key);
+
+typedef enum {
+  MUNIT_TEST_OPTION_NONE             = 0,
+  MUNIT_TEST_OPTION_SINGLE_ITERATION = 1 << 0,
+  MUNIT_TEST_OPTION_TODO             = 1 << 1
+} MunitTestOptions;
+
+typedef MunitResult (* MunitTestFunc)(const MunitParameter params[], void* user_data_or_fixture);
+typedef void*       (* MunitTestSetup)(const MunitParameter params[], void* user_data);
+typedef void        (* MunitTestTearDown)(void* fixture);
+
+typedef struct {
+  char*               name;
+  MunitTestFunc       test;
+  MunitTestSetup      setup;
+  MunitTestTearDown   tear_down;
+  MunitTestOptions    options;
+  MunitParameterEnum* parameters;
+} MunitTest;
+
+typedef enum {
+  MUNIT_SUITE_OPTION_NONE = 0
+} MunitSuiteOptions;
+
+typedef struct MunitSuite_ MunitSuite;
+
+struct MunitSuite_ {
+  char*             prefix;
+  MunitTest*        tests;
+  MunitSuite*       suites;
+  unsigned int      iterations;
+  MunitSuiteOptions options;
+};
+
+int munit_suite_main(const MunitSuite* suite, void* user_data, int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
+
+/* Note: I'm not very happy with this API; it's likely to change if I
+ * figure out something better.  Suggestions welcome. */
+
+typedef struct MunitArgument_ MunitArgument;
+
+struct MunitArgument_ {
+  char* name;
+  munit_bool (* parse_argument)(const MunitSuite* suite, void* user_data, int* arg, int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
+  void (* write_help)(const MunitArgument* argument, void* user_data);
+};
+
+int munit_suite_main_custom(const MunitSuite* suite,
+                            void* user_data,
+                            int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)],
+                            const MunitArgument arguments[]);
+
+#if defined(MUNIT_ENABLE_ASSERT_ALIASES)
+
+#define assert_true(expr) munit_assert_true(expr)
+#define assert_false(expr) munit_assert_false(expr)
+#define assert_char(a, op, b) munit_assert_char(a, op, b)
+#define assert_uchar(a, op, b) munit_assert_uchar(a, op, b)
+#define assert_short(a, op, b) munit_assert_short(a, op, b)
+#define assert_ushort(a, op, b) munit_assert_ushort(a, op, b)
+#define assert_int(a, op, b) munit_assert_int(a, op, b)
+#define assert_uint(a, op, b) munit_assert_uint(a, op, b)
+#define assert_long(a, op, b) munit_assert_long(a, op, b)
+#define assert_ulong(a, op, b) munit_assert_ulong(a, op, b)
+#define assert_llong(a, op, b) munit_assert_llong(a, op, b)
+#define assert_ullong(a, op, b) munit_assert_ullong(a, op, b)
+#define assert_size(a, op, b) munit_assert_size(a, op, b)
+#define assert_float(a, op, b) munit_assert_float(a, op, b)
+#define assert_double(a, op, b) munit_assert_double(a, op, b)
+#define assert_ptr(a, op, b) munit_assert_ptr(a, op, b)
+
+#define assert_int8(a, op, b) munit_assert_int8(a, op, b)
+#define assert_uint8(a, op, b) munit_assert_uint8(a, op, b)
+#define assert_int16(a, op, b) munit_assert_int16(a, op, b)
+#define assert_uint16(a, op, b) munit_assert_uint16(a, op, b)
+#define assert_int32(a, op, b) munit_assert_int32(a, op, b)
+#define assert_uint32(a, op, b) munit_assert_uint32(a, op, b)
+#define assert_int64(a, op, b) munit_assert_int64(a, op, b)
+#define assert_uint64(a, op, b) munit_assert_uint64(a, op, b)
+
+#define assert_double_equal(a, b, precision) munit_assert_double_equal(a, b, precision)
+#define assert_string_equal(a, b) munit_assert_string_equal(a, b)
+#define assert_string_not_equal(a, b) munit_assert_string_not_equal(a, b)
+#define assert_memory_equal(size, a, b) munit_assert_memory_equal(size, a, b)
+#define assert_memory_not_equal(size, a, b) munit_assert_memory_not_equal(size, a, b)
+#define assert_ptr_equal(a, b) munit_assert_ptr_equal(a, b)
+#define assert_ptr_not_equal(a, b) munit_assert_ptr_not_equal(a, b)
+#define assert_ptr_null(ptr) munit_assert_null_equal(ptr)
+#define assert_ptr_not_null(ptr) munit_assert_not_null(ptr)
+
+#define assert_null(ptr) munit_assert_null(ptr)
+#define assert_not_null(ptr) munit_assert_not_null(ptr)
+
+#endif /* defined(MUNIT_ENABLE_ASSERT_ALIASES) */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* !defined(MUNIT_H) */
+
+#if defined(MUNIT_ENABLE_ASSERT_ALIASES)
+#  if defined(assert)
+#    undef assert
+#  endif
+#  define assert(expr) munit_assert(expr)
+#endif
-- 
2.34.1


^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH olang 2/2] tests: add integration test setup
  2024-02-15 16:21 [PATCH olang 0/2] Add integration tests Carlos Maniero
  2024-02-15 16:21 ` [PATCH olang 1/2] tests: add munit testing framework file Carlos Maniero
@ 2024-02-15 16:21 ` Carlos Maniero
  2024-02-15 16:27   ` [olang/patches/.build.yml] build success builds.sr.ht
  2024-02-15 22:21   ` [PATCH olang 2/2] tests: add integration test setup Johnny Richard
  1 sibling, 2 replies; 83+ messages in thread
From: Carlos Maniero @ 2024-02-15 16:21 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Carlos Maniero

This is a basic setup for integration tests which includes:

- a *cli_runner* helper file to provide an interface to interact with
  the CLI.
- a simple test that validates if the compiler is returning zero status
  code when a file is provided.

At this point the compiler still doing nothing making all this bootstrap
just a fancy way to check if the compiler was compiled properly.

Signed-off-by: Carlos Maniero <carlos@maniero.me>
---
 .build.yml                     |  6 ++-
 Makefile                       | 16 ++++++++
 tests/integration/Makefile     | 27 +++++++++++++
 tests/integration/cli_runner.c | 71 ++++++++++++++++++++++++++++++++++
 tests/integration/cli_runner.h | 27 +++++++++++++
 tests/integration/cli_test.c   | 39 +++++++++++++++++++
 6 files changed, 185 insertions(+), 1 deletion(-)
 create mode 100644 tests/integration/Makefile
 create mode 100644 tests/integration/cli_runner.c
 create mode 100644 tests/integration/cli_runner.h
 create mode 100644 tests/integration/cli_test.c

diff --git a/.build.yml b/.build.yml
index 3aebfcf..7ed89eb 100644
--- a/.build.yml
+++ b/.build.yml
@@ -8,7 +8,11 @@ sources:
 tasks:
   - lint: |
       cd olang
-      make linter
+      make linter-all
   - build: |
       cd olang
       make
+  - integration-test: |
+      cd olang
+      make integration-test
+
diff --git a/Makefile b/Makefile
index 2a23b59..fa3df6c 100644
--- a/Makefile
+++ b/Makefile
@@ -20,9 +20,25 @@ $(BUILD_DIR):
 linter: $(SRCS) $(HEADERS)
 	clang-format --dry-run --Werror $?
 
+.PHONY: linter-all
+linter-all: $(SRCS) $(HEADERS)
+	make linter
+	make -C tests/integration/ linter
+
+
 .PHONY: linter-fix
 linter-fix: $(SRCS) $(HEADERS)
 	clang-format -i $?
 
+.PHONY: linter-fix-all
+linter-fix-all: $(SRCS) $(HEADERS)
+	make linter-fix
+	make -C tests/integration/ linter-fix
+
+.PHONY: integration-test
+integration-test:
+	make
+	make -C tests/integration/
+
 $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
 	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/tests/integration/Makefile b/tests/integration/Makefile
new file mode 100644
index 0000000..a42f787
--- /dev/null
+++ b/tests/integration/Makefile
@@ -0,0 +1,27 @@
+SRCS        := $(wildcard *_test.c)
+TO_LINT     := $(filter-out munit.c munit.h,$(wildcard *.c *.h))
+OBJS        := $(patsubst %_test.c, %_test.o, $(SRCS))
+CFLAGS      := -I../../src
+TESTS       := $(patsubst %_test.c, %_test, $(SRCS))
+EXEC_TESTS  := $(patsubst %_test, ./%_test, $(TESTS))
+
+.PHONY: all
+all: munit.o cli_runner.o $(TESTS)
+	@for file in $(EXEC_TESTS); do \
+                ./"$$file"; \
+        done
+
+.PHONY: clean
+clean:
+	$(RM) *.o *_test
+
+.PHONY: linter
+linter: $(TO_LINT)
+	clang-format --dry-run --Werror $?
+
+.PHONY: linter-fix
+linter-fix: $(TO_LINT)
+	clang-format -i $?
+
+cli_test: munit.o cli_runner.o cli_test.o
+	$(CC) $? $(CFLAGS) -o $@
diff --git a/tests/integration/cli_runner.c b/tests/integration/cli_runner.c
new file mode 100644
index 0000000..cd7ba22
--- /dev/null
+++ b/tests/integration/cli_runner.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 olang maintainers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+#include "cli_runner.h"
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define OLANG_COMPILER_PATH "../../0c"
+
+int _compiler_exists_already_checked = 0;
+
+void
+_assert_compiler_exists()
+{
+    {
+        if (_compiler_exists_already_checked == 1) {
+            return;
+        }
+
+        _compiler_exists_already_checked = 1;
+    }
+
+    FILE *file;
+    if ((file = fopen(OLANG_COMPILER_PATH, "r"))) {
+        fclose(file);
+        return;
+    }
+
+    assert(false && "Compiler not found. Build the compiler before executing tests.");
+}
+
+void
+_create_tmp_file_name(char *file_name)
+{
+    sprintf(file_name, "%s/olang_programXXXXXX", P_tmpdir);
+    int fd = mkstemp(file_name);
+    assert(fd != -1 && "Could not create a tmp file");
+    close(fd);
+}
+
+cli_result_t
+cli_runner_compile_file(char *src)
+{
+    _assert_compiler_exists();
+
+    cli_result_t result;
+    _create_tmp_file_name(result.binary_loc);
+
+    char command[1024];
+    sprintf(command, "%s -o %s %s", OLANG_COMPILER_PATH, result.binary_loc, src);
+
+    result.exit_code = system(command);
+    return result;
+}
diff --git a/tests/integration/cli_runner.h b/tests/integration/cli_runner.h
new file mode 100644
index 0000000..0df7f2d
--- /dev/null
+++ b/tests/integration/cli_runner.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 olang maintainers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef CLI_RUNNER_H
+#define CLI_RUNNER_H
+typedef struct cli_result_t
+{
+    int exit_code;
+    char binary_loc[255];
+} cli_result_t;
+
+cli_result_t
+cli_runner_compile_file(char *src);
+#endif
diff --git a/tests/integration/cli_test.c b/tests/integration/cli_test.c
new file mode 100644
index 0000000..c7a9557
--- /dev/null
+++ b/tests/integration/cli_test.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 olang maintainers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+#define MUNIT_ENABLE_ASSERT_ALIASES
+#include "cli_runner.h"
+#include "munit.h"
+
+static MunitResult
+test_cli_hello_file(const MunitParameter params[], void *user_data_or_fixture)
+{
+    cli_result_t compilation_result = cli_runner_compile_file("../../examples/hello.olang");
+    munit_assert_int(compilation_result.exit_code, ==, 0);
+    return MUNIT_OK;
+}
+
+static MunitTest tests[] = { { "/test_cli_hello_file", test_cli_hello_file, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
+                             { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } };
+
+static const MunitSuite suite = { "/cli_test", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE };
+
+int
+main(int argc, char *argv[])
+{
+    return munit_suite_main(&suite, NULL, argc, argv);
+    return EXIT_SUCCESS;
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-15 16:21 ` [PATCH olang 2/2] tests: add integration test setup Carlos Maniero
@ 2024-02-15 16:27   ` builds.sr.ht
  2024-02-15 22:21   ` [PATCH olang 2/2] tests: add integration test setup Johnny Richard
  1 sibling, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-15 16:27 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 17s

[Add integration tests][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49542
[1]: mailto:carlos@maniero.me

✓ #1150776 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1150776

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH olang 2/2] tests: add integration test setup
  2024-02-15 22:21   ` [PATCH olang 2/2] tests: add integration test setup Johnny Richard
@ 2024-02-15 22:07     ` Carlos Maniero
  2024-02-16  2:27     ` Carlos Maniero
  1 sibling, 0 replies; 83+ messages in thread
From: Carlos Maniero @ 2024-02-15 22:07 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel



^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH olang 2/2] tests: add integration test setup
  2024-02-15 16:21 ` [PATCH olang 2/2] tests: add integration test setup Carlos Maniero
  2024-02-15 16:27   ` [olang/patches/.build.yml] build success builds.sr.ht
@ 2024-02-15 22:21   ` Johnny Richard
  2024-02-15 22:07     ` Carlos Maniero
  2024-02-16  2:27     ` Carlos Maniero
  1 sibling, 2 replies; 83+ messages in thread
From: Johnny Richard @ 2024-02-15 22:21 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

In general it looks good, no big issues at all.  I just would like to
discuss few topics and see your point of view.

On Thu, Feb 15, 2024 at 01:21:46PM -0300, Carlos Maniero wrote:
> This is a basic setup for integration tests which includes:
> 
> - a *cli_runner* helper file to provide an interface to interact with
>   the CLI.
> - a simple test that validates if the compiler is returning zero status

nitpick: s/status/exit/

>   code when a file is provided.
> 
> At this point the compiler still doing nothing making all this bootstrap
> just a fancy way to check if the compiler was compiled properly.
> 
> Signed-off-by: Carlos Maniero <carlos@maniero.me>
> ---
>  .build.yml                     |  6 ++-
>  Makefile                       | 16 ++++++++
>  tests/integration/Makefile     | 27 +++++++++++++
>  tests/integration/cli_runner.c | 71 ++++++++++++++++++++++++++++++++++
>  tests/integration/cli_runner.h | 27 +++++++++++++
>  tests/integration/cli_test.c   | 39 +++++++++++++++++++

What is the motivation behind segregate integration tests from unit
tests?

> diff --git a/Makefile b/Makefile
> index 2a23b59..fa3df6c 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -20,9 +20,25 @@ $(BUILD_DIR):
>  linter: $(SRCS) $(HEADERS)
>  	clang-format --dry-run --Werror $?
>  
> +.PHONY: linter-all
> +linter-all: $(SRCS) $(HEADERS)
> +	make linter

nitpick: Let's use $(MAKE) instead of make directly.

> +	make -C tests/integration/ linter
> +
> +
>  .PHONY: linter-fix
>  linter-fix: $(SRCS) $(HEADERS)
>  	clang-format -i $?
>  
> +.PHONY: linter-fix-all
> +linter-fix-all: $(SRCS) $(HEADERS)

What do you think about the /linter-fix/ and /linter/ scan all files
instead of introducing new targets with -all suffix?

> +	make linter-fix
> +	make -C tests/integration/ linter-fix
> +
> +.PHONY: integration-test
> +integration-test:

What do you think about adding a /check/ target that runs all tests on the
project.

> diff --git a/tests/integration/cli_runner.c b/tests/integration/cli_runner.c
> new file mode 100644
> index 0000000..cd7ba22
> --- /dev/null
> +++ b/tests/integration/cli_runner.c
> @@ -0,0 +1,71 @@
> +/*
> + * Copyright (C) 2024 olang maintainers
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <https://www.gnu.org/licenses/>.
> + */
> +#include "cli_runner.h"
> +#include <assert.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#define OLANG_COMPILER_PATH "../../0c"
> +
> +int _compiler_exists_already_checked = 0;

nitpick: I cannot see a big benefit of adding an underscore for this
property neither for methods.  I understand you want to communicate that
it should not be access by other sources.

What do you think about making these "_" properties and functions
static?
> +
> +void
> +_assert_compiler_exists()
> +{
> +    {
> +        if (_compiler_exists_already_checked == 1) {
> +            return;
> +        }
> +
> +        _compiler_exists_already_checked = 1;
> +    }
> +
> +    FILE *file;
> +    if ((file = fopen(OLANG_COMPILER_PATH, "r"))) {

suggestion: We could be more clear what is under test like bellow:

    FILE *file = file = fopen(OLANG_COMPILER_PATH, "r");
    if (file != NULL) {

> +        fclose(file);
> +        return;
> +    }
> +
> +    assert(false && "Compiler not found. Build the compiler before executing tests.");

nitpick: We could use a /perror/ followed by a /exit/ to be more
descriptive on the message error.

    perror("Compiler not found. Build the compiler before executing tests.");
    exit(EXIT_FAILURE);

What do you think?

> +}
> +
> +void
> +_create_tmp_file_name(char *file_name)
> +{
> +    sprintf(file_name, "%s/olang_programXXXXXX", P_tmpdir);
> +    int fd = mkstemp(file_name);
> +    assert(fd != -1 && "Could not create a tmp file");

suggestion: Could we also use /perror/ and /exit/ here as well?

> diff --git a/tests/integration/cli_runner.h b/tests/integration/cli_runner.h
> new file mode 100644
> index 0000000..0df7f2d
> --- /dev/null
> +++ b/tests/integration/cli_runner.h
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright (C) 2024 olang maintainers
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <https://www.gnu.org/licenses/>.
> + */
> +#ifndef CLI_RUNNER_H
> +#define CLI_RUNNER_H
> +typedef struct cli_result_t
> +{
> +    int exit_code;
> +    char binary_loc[255];

What is binary_loc? Does it means location or path?

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH olang 2/2] tests: add integration test setup
  2024-02-15 22:21   ` [PATCH olang 2/2] tests: add integration test setup Johnny Richard
  2024-02-15 22:07     ` Carlos Maniero
@ 2024-02-16  2:27     ` Carlos Maniero
  2024-02-16  8:17       ` Johnny Richard
  1 sibling, 1 reply; 83+ messages in thread
From: Carlos Maniero @ 2024-02-16  2:27 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

Thanks for the feedback, I'll answer some of you questions here. The
ones I didn't address here is because I just agree and the fix will be
sent on the next patchset.

> What is the motivation behind segregate integration tests from unit
> tests?

I might be dreaming at this point, but I know you kinda share the same
dream of making olang a self-hosted language. With this in mind, I think
it is a good idea to have these two levels of testing: unit tests will
test c-related stuff and implementation details, while integration tests
will test the compiler features by calling the compiler with a
*system()* call.

When we start to rewrite the compiler in olang, the unit tests may
change because we gonna change the design of the compiler to remove the
"c-accent". On the other hand, integration tests should not be touched
during the rewriting process because the features will stay the same.

> What do you think about the /linter-fix/ and /linter/ scan all files
> instead of introducing new targets with -all suffix?

I like to have small targets that are composed this brings more
flexibility to my workflow, but I have no strong opinion with this one.
I'll change they in the reviewed patchset.

> nitpick: I cannot see a big benefit of adding an underscore for this
> property neither for methods.  I understand you want to communicate that
> it should not be access by other sources.
> 
> What do you think about making these "_" properties and functions
> static?

I love the idea.

> What is binary_loc? Does it means location or path?

Yeah! that name sucks. It is the compilation result binary path.
WDYT about rename it to *program_path*?

And sorry about the previous empty email, I've no idea what happened.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH olang 2/2] tests: add integration test setup
  2024-02-16  2:27     ` Carlos Maniero
@ 2024-02-16  8:17       ` Johnny Richard
  0 siblings, 0 replies; 83+ messages in thread
From: Johnny Richard @ 2024-02-16  8:17 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

Thanks for the reply.

On Thu, Feb 15, 2024 at 11:27:00PM -0300, Carlos Maniero wrote:
> > What is the motivation behind segregate integration tests from unit
> > tests?
> 
> I might be dreaming at this point, but I know you kinda share the same
> dream of making olang a self-hosted language. With this in mind, I think
> it is a good idea to have these two levels of testing: unit tests will
> test c-related stuff and implementation details, while integration tests
> will test the compiler features by calling the compiler with a
> *system()* call.
> 
> When we start to rewrite the compiler in olang, the unit tests may
> change because we gonna change the design of the compiler to remove the
> "c-accent". On the other hand, integration tests should not be touched
> during the rewriting process because the features will stay the same.

Yeah, we do share the same dream :), but maybe is too early to optimize
it.  In the end, everything is a binary, and we are using Makefile to
run the tests, I cannot see any problem on having two different
languages within test folder.

Anyhow we can keep it like this.  I don't have a strong opinion to be
honest.

> > What is binary_loc? Does it means location or path?
> 
> Yeah! that name sucks. It is the compilation result binary path.
> WDYT about rename it to *program_path*?

I think /loc/ also works. I was trying to confirm if I understood
correctly.  But sure, /program_path/ is clearer.

> And sorry about the previous empty email, I've no idea what happened.

No worries.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-27 23:07 [PATCH olang v2 1/2] ast: add function call node Johnny Richard
@ 2024-09-27 21:11 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-27 21:11 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 19s

[frontend: Add function calls parsing][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55225
[1]: mailto:johnny@johnnyrichard.com

✓ #1338817 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1338817

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-25 23:20 [PATCH olang v1 2/2] parser: add support for parsing function calls Johnny Richard
@ 2024-09-25 21:22 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-25 21:22 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 20s

[frontend: Add function calls parsing][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55199
[1]: mailto:johnny@johnnyrichard.com

✓ #1337043 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1337043

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-25 18:39 [PATCH olang] tests: fix diff error output Carlos Maniero
@ 2024-09-25 18:39 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-25 18:39 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 19s

[tests: fix diff error output][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55198
[1]: mailto:carlos@maniero.me

✓ #1336951 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1336951

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-25 18:30 [PATCH olang] parser: parse multiple function into a single translation unit Carlos Maniero
@ 2024-09-25 18:31 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-25 18:31 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 19s

[parser: parse multiple function into a single translation unit][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55197
[1]: mailto:carlos@maniero.me

✓ #1336943 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1336943

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-23 22:19 [PATCH olang v1 2/3] lexer: add token comma Johnny Richard
@ 2024-09-23 22:23 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-23 22:23 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 19s

[parse function definition params][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55183
[1]: mailto:johnny@johnnyrichard.com

✓ #1335469 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1335469

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-23 11:43 [PATCH olang 2/2] ast: permit multi declarations on translation unit Carlos Maniero
@ 2024-09-23 11:44 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-23 11:44 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 20s

[Rename program to translation unit][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55177
[1]: mailto:carlos@maniero.me

✓ #1335028 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1335028

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-23 10:11 [PATCH olang v1 3/3] naming: rename all identifier symbols to id Carlos Maniero
@ 2024-09-23 10:12 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-23 10:12 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 19s

[Housekeeping: resolve a few FIXMEs related to code style][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55176
[1]: mailto:carlos@maniero.me

✓ #1334988 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1334988

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-22  0:46 [PATCH olang v2 4/4] codegen: operate mov instructions based on the symbol's type Carlos Maniero
@ 2024-09-22  0:47 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-22  0:47 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 20s

[extend unsined integers types (u8, u16, u64)][0] v2 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55161
[1]: mailto:carlos@maniero.me

✓ #1334228 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1334228

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-21 21:02 [PATCH olang v1 2/2] tests: build: add parallelization support for unit tests Johnny Richard
@ 2024-09-21 21:05 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-21 21:05 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 20s

[tests: build: improve makefile for tests][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55158
[1]: mailto:johnny@johnnyrichard.com

✓ #1334090 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1334090

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-21  8:25 [PATCH olang 5/5] codegen: perform mov instructions based on variable type Carlos Maniero
@ 2024-09-21  8:26 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-21  8:26 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 21s

[extend unsined integers types (u8, u16, u64)][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55142
[1]: mailto:carlos@maniero.me

✓ #1333732 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1333732

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-21  1:13 [PATCH olang 5/5] codegen: preserve function's variable stack location Carlos Maniero
@ 2024-09-21  1:13 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-21  1:13 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 20s

[fix multiple variables][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55133
[1]: mailto:carlos@maniero.me

✓ #1333568 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1333568

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-21  0:20 [PATCH olang v1 3/3] codegen: add support scopes and symbols lookups for var Johnny Richard
@ 2024-09-21  0:23 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-21  0:23 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 21s

[compiler: enable full compilation for vars][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55131
[1]: mailto:johnny@johnnyrichard.com

✓ #1333519 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1333519

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-17 15:14 [PATCH olang] cli: add libc error handling Carlos Maniero
@ 2024-09-17 15:15 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-17 15:15 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 20s

[cli: add libc error handling][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55079
[1]: mailto:carlos@maniero.me

✓ #1330161 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1330161

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-17 13:43 [PATCH olang v1] remove unused examples programs Johnny Richard
@ 2024-09-17 11:43 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-17 11:43 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 20s

[remove unused examples programs][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55077
[1]: mailto:johnny@johnnyrichard.com

✓ #1329949 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1329949

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-17 12:46 [PATCH olang v1 4/4] docs: info: add instructions to install/uninstall olang Johnny Richard
@ 2024-09-17 10:48 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-17 10:48 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 20s

[build: add install and uninstall targets][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55076
[1]: mailto:johnny@johnnyrichard.com

✓ #1329923 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1329923

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-16 16:29 [PATCH olang v1 3/3] docs: remove pandoc dependency for man docs Johnny Richard
@ 2024-09-16 14:31 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-16 14:31 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 50s

[docs: remove pandoc dependency ][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55062
[1]: mailto:johnny@johnnyrichard.com

✓ #1329317 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1329317

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-09-11  1:03 [PATCH olang v1 2/2] parser: add var definition and reference support Johnny Richard
@ 2024-09-10 23:05 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-09-10 23:05 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 35s

[parser: implement variable definition][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/54983
[1]: mailto:johnny@johnnyrichard.com

✓ #1324659 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1324659

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-08-25 13:16 [PATCH olang v2 2/2] codegen: x86_64: implement binary operations Johnny Richard
@ 2024-08-25 13:26 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-08-25 13:26 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 37s

[codegen: x86_64: implement binary operations][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/54696
[1]: mailto:johnny@johnnyrichard.com

✓ #1311572 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1311572

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-08-21  3:39 [PATCH olang 1/2] tests: add comment based integration tests mechanism Carlos Maniero
@ 2024-08-21  3:41 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-08-21  3:41 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 36s

[tests: create a text-based integrations test][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/54588
[1]: mailto:carlos@maniero.me

✓ #1308300 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1308300

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-08-13 18:55 [PATCH olang v2 2/2] ast: inline ast_node_data_t union typedef Johnny Richard
@ 2024-08-13 18:04 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-08-13 18:04 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 32s

[ast: refactor: inline union typedefs][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/54447
[1]: mailto:johnny@johnnyrichard.com

✓ #1302393 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1302393

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-05-12 14:30 [PATCH olang 4/4] tests: print integration tests TODOs Carlos Maniero
@ 2024-05-12 14:31 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-05-12 14:31 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 51s

[comment based integration tests][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51804
[1]: mailto:carlos@maniero.me

✓ #1219016 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1219016

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-04-27 12:14 [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Johnny Richard
@ 2024-04-27 11:21 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-04-27 11:21 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 43s

[codegen: x86_64: implement binary operations][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51409
[1]: mailto:johnny@johnnyrichard.com

✓ #1206119 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1206119

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-04-18 23:08 [PATCH olang v1] parser: fix parse expression with binop chain Johnny Richard
@ 2024-04-18 22:11 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-04-18 22:11 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 47s

[parser: fix parse expression with binop chain][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51128
[1]: mailto:johnny@johnnyrichard.com

✓ #1199392 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1199392

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-04-18 22:18 [PATCH olang v1] parser: add missing <= and >= binary operators Johnny Richard
@ 2024-04-18 21:22 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-04-18 21:22 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 43s

[parser: add missing <= and >= binary operators][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51123
[1]: mailto:johnny@johnnyrichard.com

✓ #1199375 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1199375

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-04-18 21:58 [PATCH olang v1] docs: spec: add %, <= and >= binary operators Johnny Richard
@ 2024-04-18 21:02 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-04-18 21:02 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 44s

[docs: spec: add %, <= and >= binary operators][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51122
[1]: mailto:johnny@johnnyrichard.com

✓ #1199362 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1199362

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-04-16 23:51 [PATCH olang v1] Revert "docs: spec: postpone assignment operators" Johnny Richard
@ 2024-04-16 22:56 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-04-16 22:56 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 43s

[Revert "docs: spec: postpone assignment operators"][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51078
[1]: mailto:johnny@johnnyrichard.com

✓ #1197726 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1197726

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-04-16 23:35 [PATCH olang v2] docs: spec: add binary expressions Johnny Richard
@ 2024-04-16 22:40 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-04-16 22:40 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 44s

[docs: spec: add binary expressions][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51076
[1]: mailto:johnny@johnnyrichard.com

✓ #1197709 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1197709

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-04-15 18:20 [PATCH olang v1] spec: ebnf: add binary expressions Johnny Richard
@ 2024-04-15 17:43 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-04-15 17:43 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 44s

[spec: ebnf: add binary expressions][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51036
[1]: mailto:johnny@johnnyrichard.com

✓ #1196562 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1196562

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-04-08  4:38 [PATCH olang v2 2/2] docs: spec: add variables and constants specification Carlos Maniero
@ 2024-04-08  4:39 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-04-08  4:39 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 39s

[docs: variables specification][0] v2 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50820
[1]: mailto:carlos@maniero.me

✓ #1189894 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1189894

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-29  1:59 [PATCH olang] linter: turn off clang-format to keep retro compatibility with v16 Johnny Richard
@ 2024-03-29  0:59 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-29  0:59 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 37s

[linter: turn off clang-format to keep retro compatibility with v16][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50521
[1]: mailto:johnny@johnnyrichard.com

✓ #1181503 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1181503

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-29  0:33 [PATCH olang] site: change look and feel and rewrite home introduction section Johnny Richard
@ 2024-03-28 23:33 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-28 23:33 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 38s

[site: change look and feel and rewrite home introduction section][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50517
[1]: mailto:johnny@johnnyrichard.com

✓ #1181439 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1181439

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-24 16:12 [PATCH olang v3] docs: create o programming language spec Johnny Richard
@ 2024-03-24 15:16 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-24 15:16 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 40s

[docs: create o programming language spec][0] v3 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50408
[1]: mailto:johnny@johnnyrichard.com

✓ #1177304 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1177304

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-19 20:18 [PATCH olang v2] docs: create o programming language spec Johnny Richard
@ 2024-03-19 19:20 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-19 19:20 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 39s

[docs: create o programming language spec][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50320
[1]: mailto:johnny@johnnyrichard.com

✓ #1173074 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1173074

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-19 19:57 [PATCH olang v1 3/3] codegen: add compiler support to linux aarch64 arch Johnny Richard
@ 2024-03-19 19:00 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-19 19:00 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 38s

[fe: add compiler support to linux aarch64][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50318
[1]: mailto:johnny@johnnyrichard.com

✓ #1173054 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1173054

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-18  8:39 [PATCH olang v3 3/3] parser: add all binary operation expressions Johnny Richard
@ 2024-03-18  7:43 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-18  7:43 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 40s

[fe: add binary operation expr support][0] v3 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50288
[1]: mailto:johnny@johnnyrichard.com

✓ #1171874 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1171874

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-17 21:29 [PATCH olang v2 3/3] parser: add all binary operation expressions Johnny Richard
@ 2024-03-17 20:37 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-17 20:37 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 38s

[frontend: add binary operation expr support][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50275
[1]: mailto:johnny@johnnyrichard.com

✓ #1171442 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1171442

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [olang/patches/.build.yml] build success
  2024-03-14  4:29   ` Ricardo Kagawa
@ 2024-03-14 22:43     ` Johnny Richard
  0 siblings, 0 replies; 83+ messages in thread
From: Johnny Richard @ 2024-03-14 22:43 UTC (permalink / raw)
  To: Ricardo Kagawa; +Cc: ~johnnyrichard/olang-devel

Thank you very much for you contribution, I love it <3.

nitpick for next replies:

    1) You've replied to the CI build reply.  Next time try to reply to
       the right thread.

    2) Your message has few weird line breaks.  I don't know why it's
       happening (noticed you are using Thunderbird).  However, you can
       make sure your setup is correctly configured to send plain text
       emails by visiting this website https://useplaintext.email/

On Thu, Mar 14, 2024 at 01:29:09AM -0300, Ricardo Kagawa wrote:
> >> This grammar adds the token SEMICOLON (';') for every statement.  I know
> we
> >> agreed make it optional, but the SEMICOLON makes the parser much more
> >> convenient to implement.
> >>
> >> And this is the first topic I would like to discuss. Let me know if you
> >> agree otherwise I can adapt the grammar to make SEMICOLON optional.
> >
> > (...) Therefore, I'm curious about your statement that using a
> > semicolon makes the parser much more convenient to implement. Could you
> > elaborate on this? Have you encountered any new considerations that might
> > complicate the implementation?
> 
> My limited understanding is that the semicolon would indeed be more
> convenient, as it would be a definitive end-of-statement symbol,
> requiring no lookahead to resolve as such. The LF token could be
> ambiguous on its own (between end-of-statement and white space), so
> some lookahead would be required to resolve it.

You are right about it.  I had to implement the lookahead capability in
order to skip LF tokens.

> But it should be alright, as long as the language remains context-free.
> Even if it becomes ambiguous, non-deterministic, or requires a long
> lookahead. Ideally it should be determinitstic for linear time
> performance, but it seems there are parsers that can run close to it in
> the average case, as long as the language remains close to
> deterministic.
> 
> And I don't have a strong opinion on the semicolon issue, except that
> it must be an option. But whatever we do, we must avoid the following
> pitfall from JavaScript:
> 
> ```javascript
> example
> ;(x)
> ```
> 
> The semicolon is mandatory here, because otherwise `(x)` is handled as
> an argument list, and `example` would be called as a function. That is,
> it would be a multi-line statement, instead of two separate statements.
> 
> And why anyone would do this?
> 
> ```javascript
> const x = y.example
> ;(() => {
>   console.log(x)
> })()
> ```

I strong agree on avoid those odd JavaScript design.  I think we can
continue with optional SEMICOLON.  I also think it makes a better
programmer experience.

> >> The grammar was made by using a EBNF evaluator tool[1].
> >>
> >> [1]: https://mdkrajnak.github.io/ebnftest/
> >
> > I would add this link at the markdown, so then people can play with it.
> 
> I would make an even stronger argument for including the link in the
> docs. A good language specification also specifies which language
> specification grammar is used for the specification itself. And the
> EBNF in particular is not properly standardized, so you really need to
> specify which EBNF variant you are using.
> 
> The link should thus be good enough to refer to the EBNF implementation
> used in this specification, although a permanent (version locked) link
> would be better.

Sure, I can add it to the document.  I'm not sure how you want to
version lock this variant.  Should I add a specific github/git tag
version to the document?

> As for my revision of the grammar:

I liked all comments and definitely it seems to be better version.  In
my option we can start with you changes and keep this document alive for
future discussion.  Not sure about Carlos.  Let see his thoughts on that
as well.

> Further discussion:
> 
> - Is the language going to support Unicode? If so, `<alpha>` could use
>   the _L:Letter_ Unicode category instead of being limited to
>   `[a-zA-Z]`. But the EBNF tool does not support Unicode categories in
>   its regular expressions (it does not support flags). Also don't
>   forget to rename it to `<letter>` in that case.
> 
>     - It would help developers in non-English speaking countries, but it
>       could be difficult to work with multi-byte characters and Unicode
>       normalization.

I lack knowledge to answer this question right know.  I would say to
keep it simple as much as we can on this earlier stage (ASCII only)
unless you have a big concern.

> - There are more linear space and line break characters than the ones
>   included here, even within ASCII, although they are not all that
>   important. Even more in Unicode (some under _Cc:Other/control_,
>   others under _Z:Separator_). Should we support them?

Let's add the remaining ASCII ones meanwhile.

> - The function definition could accept a single expression as an
>   alternative to its `<block>`, similar to Kotlin.

Scala also has this capability.  But I think it doesn't fit well in our
current function declaration:

    fn f(): u32 <statement>
               ^
               If we don't add a token in here like **=** it will be very
               weird.

No strong options here to be honest.

> - The integer literal could include optional underline separators for
>   readability. Just need to be careful not to start with underline, to
>   avoid ambiguity with identifiers.

I like that.  We can have it as well.

> - I guess we don't have to support the full set of Unicode digits, since
>   we don't know if these digits would even be decimal in the first
>   place. The numbering system could be very different from our own, so
>   it is likely not feasible to support them.

Perhaps we could postpone the Unicode support?

> - I have not checked if this syntax would avoid that edge case with
>   JavaScript I mentioned in the beginning. I might check that next
>   time (I'm still not sure of how).

Maybe we are going to discovery it on the implementation process.

> - It might seem strange that I included semantic non-terminals here,
>   despite having removed non-terminals for symbols and keywords. I can't
>   say for sure, since this is my first time trying this style, but I
>   suspect that besides making the language specification easier to
>   understand, the important bits to hook into in the parser will be
>   around these symbols. That is, it could simplify some work on the
>   parser.

ACK

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [olang/patches/.build.yml] build success
  2024-03-08 23:09 ` [olang/patches/.build.yml] build success builds.sr.ht
@ 2024-03-14  4:29   ` Ricardo Kagawa
  2024-03-14 22:43     ` Johnny Richard
  0 siblings, 1 reply; 83+ messages in thread
From: Ricardo Kagawa @ 2024-03-14  4:29 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: builds.sr.ht

 >> This grammar adds the token SEMICOLON (';') for every statement.  I 
know we

 >> agreed make it optional, but the SEMICOLON makes the parser much more

 >> convenient to implement.

 >>

 >> And this is the first topic I would like to discuss. Let me know if you

 >> agree otherwise I can adapt the grammar to make SEMICOLON optional.

 >

 > (...) Therefore, I'm curious about your statement that using a

 > semicolon makes the parser much more convenient to implement. Could you

 > elaborate on this? Have you encountered any new considerations that might

 > complicate the implementation?



My limited understanding is that the semicolon would indeed be more

convenient, as it would be a definitive end-of-statement symbol,

requiring no lookahead to resolve as such. The LF token could be

ambiguous on its own (between end-of-statement and white space), so

some lookahead would be required to resolve it.



But it should be alright, as long as the language remains context-free.

Even if it becomes ambiguous, non-deterministic, or requires a long

lookahead. Ideally it should be determinitstic for linear time

performance, but it seems there are parsers that can run close to it in

the average case, as long as the language remains close to

deterministic.



And I don't have a strong opinion on the semicolon issue, except that

it must be an option. But whatever we do, we must avoid the following

pitfall from JavaScript:



```javascript

example

;(x)

```



The semicolon is mandatory here, because otherwise `(x)` is handled as

an argument list, and `example` would be called as a function. That is,

it would be a multi-line statement, instead of two separate statements.



And why anyone would do this?



```javascript

const x = y.example

;(() => {

   console.log(x)

})()

```



Immediately invoked function expressions are a thing in JavaScript, and

it would not be uncommon to have some expression ending with an

identifier right before them.



 >> The grammar was made by using a EBNF evaluator tool[1].

 >>

 >> [1]: https://mdkrajnak.github.io/ebnftest/

 >

 > I would add this link at the markdown, so then people can play with it.



I would make an even stronger argument for including the link in the

docs. A good language specification also specifies which language

specification grammar is used for the specification itself. And the

EBNF in particular is not properly standardized, so you really need to

specify which EBNF variant you are using.



The link should thus be good enough to refer to the EBNF implementation

used in this specification, although a permanent (version locked) link

would be better.



----

As for my revision of the grammar:



- Separated rules into sections.

- Added optional white space around the program.

- You don't actually need non-terminal symbols for keywords. Especially

   if you are including the keyword in the symbol name.

- You don't need non-terminal symbols for symbols either, unless you

   have a more "semantic" name for it. There should not be another

   "semicolon" besides `;`, for example.

- In Johnny's version the function name is a single identifier. I don't

   know why Carlos's version made it multiple. I have made it single

   again.

- In Johnny's version the space before the return type is optional. I

   don't know why Carlos's version made it mandatory. I have made it

   optional again.

- Replaced `<identifier>` in `<function-definition>` with

   `<function-name>` to express that this identifier is the name of the

   declared function. Then, `<function-name>` is just `<identifier>`.

- Renamed `<fn-args>` to `<function-parameters>`, since parameters are

   the variables in a function declaration, while arguments are the

   values bound to those variables during function calls.

- Replaced `<type>` for `<return-type>` in `<function-declaration>` to

   express that this type identifier is the return type of the function.

   Then, `<return-type>` is just `<type>`.

- Replaced `<block>` in `<function-definition>` for `<function-body>` to

   express that this block is the body of the declared function.

- Reworked `<block>`, `<statement>` and `<end-of-statement>` to allow

   for:

     - Single statement followd by optional end-of-statement;

     - Statement list with mandatory end-of-statement between statements;

     - But the statements could be made optional, yet I did not in this

       version, as there is no `void` return type, currently.

- Replaced `<number>` in `<return-statement>` with `<expression>` to

   prepare for them in the future. The only allowed expression is still

   an integer literal, though.

- Renamed `<number>` to `<integer>`, and reworked it to actually

   represent decimal integer literals. Sequences of zero digits are now

   forbidden at the left side, but a lone zero digit is still allowed.

- Reworked `<identifier>` to better express that it starts with

   `<alpha>` or underline, followed by zero or more `<alpha>`, `<digit>`

   or underline.

- Removed `_` from `<alpha>` to better reflect the name (as underline is

   not an alphabetic character).

- Renamed `<space>` for `<ws>` to avoid ambiguity with the character

   U+0020 Space, and made it a one-or-more list. Also introduced `<ows>`

   for "optional white space". Shorter names were preferred here due to

   these symbols in particular being used very frequently.

- Also introduced `<line-break>` as either LF, CR or CRLF. Otherwise the

   CRLF sequence would be parsed as two separate line breaks. Not that it

   would matter that much, except maybe for mapping line numbers.



```

(* Entry Point *)

<program>             ::= <ows> <function-definition> <ows>



(* Functions *)

<function-definition> ::= 'fn' <ws> <function-name> <ows> 
<function-parameters> <ows> ':' <ows> <return-type> <ows> <function-body>

<function-name>       ::= <identifier>

<function-parameters> ::= '(' <ows> ')'

<return-type>         ::= <type>

<function-body>       ::= <block>



(* Statements *)

<block>               ::= '{' <ows> <statement> <ows> 
(<end-of-statement> <ows> <statement> <ows>)* <end-of-statement>? <ows> '}'

<end-of-statement>    ::= ';' | <line-break>

<statement>           ::= <return-statement>

<return-statement>    ::= 'return' <ws> <expression>



(* Expressions *)

<expression>          ::= <integer>



(* Identifiers *)

<type>                ::= 'u32'

<identifier>          ::= (<alpha> | '_') (<alpha> | <digit> | '_')*



(* Literals *)

<integer>             ::= <integer-base10>

<integer-base10>      ::= #'[1-9]' <digit>* | '0'



(* Utilities *)

<ws>                  ::= <white-space>+

<ows>                 ::= <white-space>*

<white-space>         ::= <linear-space> | <line-break>

<line-break>          ::= '\n' | '\r' | '\r\n'

<linear-space>        ::= #'[ \t]'

<alpha>               ::= #'[a-zA-Z]'

<digit>               ::= #'[0-9]'

```



Further discussion:



- Is the language going to support Unicode? If so, `<alpha>` could use

   the _L:Letter_ Unicode category instead of being limited to

   `[a-zA-Z]`. But the EBNF tool does not support Unicode categories in

   its regular expressions (it does not support flags). Also don't

   forget to rename it to `<letter>` in that case.

     - It would help developers in non-English speaking countries, but it

       could be difficult to work with multi-byte characters and Unicode

       normalization.

- There are more linear space and line break characters than the ones

   included here, even within ASCII, although they are not all that

   important. Even more in Unicode (some under _Cc:Other/control_,

   others under _Z:Separator_). Should we support them?

- The function definition could accept a single expression as an

   alternative to its `<block>`, similar to Kotlin.

- The integer literal could include optional underline separators for

   readability. Just need to be careful not to start with underline, to

   avoid ambiguity with identifiers.

- I guess we don't have to support the full set of Unicode digits, since

   we don't know if these digits would even be decimal in the first

   place. The numbering system could be very different from our own, so

   it is likely not feasible to support them.

- I have not checked if this syntax would avoid that edge case with

   JavaScript I mentioned in the beginning. I might check that next

   time (I'm still not sure of how).

- It might seem strange that I included semantic non-terminals here,

   despite having removed non-terminals for symbols and keywords. I can't

   say for sure, since this is my first time trying this style, but I

   suspect that besides making the language specification easier to

   understand, the important bits to hook into in the parser will be

   around these symbols. That is, it could simplify some work on the

   parser.


^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-13 21:21 [PATCH olang v1 3/3] parser: add basic arithmetic expressions '+' '*' '/' '-' Johnny Richard
@ 2024-03-13 20:29 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-13 20:29 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 34s

[frontend: add basic arithmetic expr support][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50195
[1]: mailto:johnny@johnnyrichard.com

✓ #1168244 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1168244

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-13 12:44 [PATCH olang v3] refactor: rename zero programming language to olang Fabio Maciel
@ 2024-03-13 12:45 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-13 12:45 UTC (permalink / raw)
  To: Fabio Maciel; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 35s

[refactor: rename zero programming language to olang][0] v3 from [Fabio Maciel][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50188
[1]: mailto:fabio@fabiomaciel.com

✓ #1167864 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1167864

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-12 19:35 [PATCH olang v1] refactor: rename zero programming language to olang Johnny Richard
@ 2024-03-12 18:40 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-12 18:40 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 36s

[refactor: rename zero programming language to olang][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50167
[1]: mailto:johnny@johnnyrichard.com

✓ #1167072 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1167072

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-11  8:48 [PATCH olang] site: change dns to o-lang.org Johnny Richard
@ 2024-03-11  7:50 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-11  7:50 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 34s

[site: change dns to o-lang.org][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50131
[1]: mailto:johnny@johnnyrichard.com

✓ #1166160 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1166160

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-09  0:05 [RFC PATCH olang v1] docs: create zero programming language specification Johnny Richard
@ 2024-03-08 23:09 ` builds.sr.ht
  2024-03-14  4:29   ` Ricardo Kagawa
  0 siblings, 1 reply; 83+ messages in thread
From: builds.sr.ht @ 2024-03-08 23:09 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 33s

[docs: create zero programming language specification][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50092
[1]: mailto:johnny@johnnyrichard.com

✓ #1164786 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1164786

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-08 22:39 [PATCH olang v2 3/3] tests: add tests for the minimal possible olang program Carlos Maniero
@ 2024-03-08 22:40 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-08 22:40 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 33s

[test: cli: cover compilation pipeline][0] v2 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50091
[1]: mailto:carlos@maniero.me

✓ #1164772 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1164772

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-08 23:13 [PATCH olang v1] ast: add ast_node root for the entire program Johnny Richard
@ 2024-03-08 22:13 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-08 22:13 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 33s

[ast: add ast_node root for the entire program][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50090
[1]: mailto:johnny@johnnyrichard.com

✓ #1164762 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1164762

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-07 23:23 [PATCH olang 3/3] tests: add tests for the minimal possible olang program Carlos Maniero
@ 2024-03-07 23:24 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-07 23:24 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 34s

[tests: cli: cover compilation pipeline][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/50070
[1]: mailto:carlos@maniero.me

✓ #1164273 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1164273

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-03-01 22:24 [PATCH olang v2 4/4] parser: create simplified parser for tiny AST Johnny Richard
@ 2024-03-01 21:32 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-03-01 21:32 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 42s

[create initial syntax analysis logic][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49932
[1]: mailto:johnny@johnnyrichard.com

✓ #1160326 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1160326

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-28 19:04 [PATCH olang v1 4/4] parser: create simplified parser for tiny AST Johnny Richard
@ 2024-02-28 18:11 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-28 18:11 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 49s

[create initial syntax analysis logic][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49873
[1]: mailto:johnny@johnnyrichard.com

✓ #1159030 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1159030

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-28 14:25 [PATCH olang v3] arena: optimization: ensure alignment memory access Carlos Maniero
@ 2024-02-28 14:26 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-28 14:26 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 44s

[arena: optimization: ensure alignment memory access][0] v3 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49869
[1]: mailto:carlos@maniero.me

✓ #1158813 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1158813

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-28 12:37 [PATCH olang v2] cli: replace memory allocation malloc -> arena Johnny Richard
@ 2024-02-28 11:39 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-28 11:39 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 45s

[cli: replace memory allocation malloc -> arena][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49866
[1]: mailto:johnny@johnnyrichard.com

✓ #1158692 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1158692

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-27 19:59 [PATCH olang v2 2/2] utils: create hash map data structure Johnny Richard
@ 2024-02-27 19:01 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-27 19:01 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 37s

[introduce hash map data structure][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49853
[1]: mailto:johnny@johnnyrichard.com

✓ #1158194 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1158194

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-24 20:40 [PATCH olang] test: fix suite name for list_test and arena_test Johnny Richard
@ 2024-02-24 19:42 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-24 19:42 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 32s

[test: fix suite name for list_test and arena_test][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49779
[1]: mailto:johnny@johnnyrichard.com

✓ #1156769 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1156769

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-22 19:09 [PATCH olang] cli: replace memory allocation malloc -> arena Johnny Richard
@ 2024-02-22 18:11 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-22 18:11 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 37s

[cli: replace memory allocation malloc -> arena][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49749
[1]: mailto:johnny@johnnyrichard.com

✓ #1155615 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1155615

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-22 18:38 [PATCH olang] docs: add DCO information on hacking page Johnny Richard
@ 2024-02-22 17:41 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-22 17:41 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 37s

[docs: add DCO information on hacking page][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49746
[1]: mailto:johnny@johnnyrichard.com

✓ #1155599 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1155599

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-22 18:24 [PATCH olang] build: rename 0c.c file to main.c Johnny Richard
@ 2024-02-22 17:26 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-22 17:26 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 37s

[build: rename 0c.c file to main.c][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49745
[1]: mailto:johnny@johnnyrichard.com

✓ #1155591 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1155591

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-21 22:20 [PATCH olang 2/2] utils: create hash map data structure Johnny Richard
@ 2024-02-21 21:24 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-21 21:24 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 44s

[introduce hash map data structure][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49732
[1]: mailto:johnny@johnnyrichard.com

✓ #1155192 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1155192

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-21 15:09 [PATCH olang v2] arena: optimization: make arena 8 bits aligned Carlos Maniero
@ 2024-02-21 15:09 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-21 15:09 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 33s

[arena: optimization: make arena 8 bits aligned][0] v2 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49723
[1]: mailto:carlos@maniero.me

✓ #1154947 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1154947

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-21  5:52 [PATCH olang] arena: optimization: make arena 8 bits aligned Carlos Maniero
@ 2024-02-21  5:53 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-21  5:53 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 35s

[arena: optimization: make arena 8 bits aligned][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49718
[1]: mailto:carlos@maniero.me

✓ #1154549 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1154549

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-20 23:37 [PATCH olang] utils: add linked-list Carlos Maniero
@ 2024-02-20 23:37 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-20 23:37 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 35s

[utils: add linked-list][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49714
[1]: mailto:carlos@maniero.me

✓ #1154366 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1154366

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-20 17:35 [PATCH olang v3] utils: add arena Carlos Maniero
@ 2024-02-20 17:41 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-20 17:41 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 33s

[utils: add arena][0] v3 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49711
[1]: mailto:carlos@maniero.me

✓ #1154191 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1154191

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-19 20:42 [PATCH olang v5 4/4] lexer: test: add integration tests for --dump-tokens Carlos Maniero
@ 2024-02-19 20:48 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-19 20:48 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 34s

[Create --dump-tokens on compiler cli][0] v5 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49685
[1]: mailto:carlos@maniero.me

✓ #1153651 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1153651

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-19  1:44 [PATCH olang v3 2/2] lexer: create --dump-tokens cli command Johnny Richard
@ 2024-02-19  0:47 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-19  0:47 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 34s

[Create --dump-tokens on compiler cli][0] v3 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49645
[1]: mailto:johnny@johnnyrichard.com

✓ #1153060 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1153060

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-18  0:50 [PATCH olang 2/2] tests: add unit tests configuration Carlos Maniero
@ 2024-02-18  0:55 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-18  0:55 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 33s

[add unit tests config][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49618
[1]: mailto:carlos@maniero.me

✓ #1152377 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1152377

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-17 20:12 [PATCH olang] docs: add mobile version Carlos Maniero
@ 2024-02-17 20:17 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-17 20:17 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 31s

[docs: add mobile version][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49612
[1]: mailto:carlos@maniero.me

✓ #1152244 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1152244

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-17 21:04 [PATCH olang] docs: deploy: replace shrt.site domain by olang.johnnyrichard.com Johnny Richard
@ 2024-02-17 20:03 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-17 20:03 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 31s

[docs: deploy: replace shrt.site domain by olang.johnnyrichard.com][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49611
[1]: mailto:johnny@johnnyrichard.com

✓ #1152239 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1152239

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-17 20:38 [PATCH olang] docs: build: fix docs publishing task Johnny Richard
@ 2024-02-17 19:37 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-17 19:37 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 31s

[docs: build: fix docs publishing task][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49609
[1]: mailto:johnny@johnnyrichard.com

✓ #1152215 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1152215

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-17 18:40 [PATCH olang v2] docs: add HACKING documentation Carlos Maniero
@ 2024-02-17 18:45 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-17 18:45 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 16s

[docs: add HACKING documentation][0] v2 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49605
[1]: mailto:carlos@maniero.me

✓ #1152165 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1152165

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-17 18:29 [PATCH olang v2] docs: add white mode support Carlos Maniero
@ 2024-02-17 18:34 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-17 18:34 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 17s

[docs: add white mode support][0] v2 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49604
[1]: mailto:carlos@maniero.me

✓ #1152150 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1152150

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-17 17:46 [PATCH olang] docs: add white-mode support Carlos Maniero
@ 2024-02-17 17:51 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-17 17:51 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 17s

[docs: add white-mode support][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49603
[1]: mailto:carlos@maniero.me

✓ #1152135 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1152135

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-17 16:22 [PATCH olang] docs: add pandoc Carlos Maniero
@ 2024-02-17 16:27 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-17 16:27 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 17s

[docs: add pandoc][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49600
[1]: mailto:carlos@maniero.me

✓ #1152071 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1152071

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-16 16:23 [PATCH olang] docs: build: add deployment script Carlos Maniero
@ 2024-02-16 16:28 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-16 16:28 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 16s

[docs: build: add deployment script][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49578
[1]: mailto:carlos@maniero.me

✓ #1151433 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1151433

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-16 16:24 [PATCH olang v2] docs: add sphinx documentation support Johnny Richard
@ 2024-02-16 15:26 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-16 15:26 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 17s

[docs: add sphinx documentation support][0] v2 from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49575
[1]: mailto:johnny@johnnyrichard.com

✓ #1151403 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1151403

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-16  8:59 [PATCH olang] docs: add sphinx documentation support Johnny Richard
@ 2024-02-16  8:01 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-16  8:01 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 16s

[docs: add sphinx documentation support][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49563
[1]: mailto:johnny@johnnyrichard.com

✓ #1151185 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1151185

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-16  3:07 [PATCH olang v3 2/2] tests: add integration test setup Carlos Maniero
@ 2024-02-16  3:12 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-16  3:12 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 15s

[add integration test][0] v3 from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49557
[1]: mailto:carlos@maniero.me

✓ #1151093 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1151093

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [olang/patches/.build.yml] build success
  2024-02-13 20:55 [PATCH olang] docs: fix git send-email config instruction Carlos Maniero
@ 2024-02-13 21:00 ` builds.sr.ht
  0 siblings, 0 replies; 83+ messages in thread
From: builds.sr.ht @ 2024-02-13 21:00 UTC (permalink / raw)
  To: Carlos Maniero; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 16s

[docs: fix git send-email config instruction][0] from [Carlos Maniero][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/49460
[1]: mailto:carlos@maniero.me

✓ #1149191 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1149191

^ permalink raw reply	[flat|nested] 83+ messages in thread

end of thread, other threads:[~2024-09-27 21:11 UTC | newest]

Thread overview: 83+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-15 16:21 [PATCH olang 0/2] Add integration tests Carlos Maniero
2024-02-15 16:21 ` [PATCH olang 1/2] tests: add munit testing framework file Carlos Maniero
2024-02-15 16:21 ` [PATCH olang 2/2] tests: add integration test setup Carlos Maniero
2024-02-15 16:27   ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-15 22:21   ` [PATCH olang 2/2] tests: add integration test setup Johnny Richard
2024-02-15 22:07     ` Carlos Maniero
2024-02-16  2:27     ` Carlos Maniero
2024-02-16  8:17       ` Johnny Richard
  -- strict thread matches above, loose matches on Subject: below --
2024-09-27 23:07 [PATCH olang v2 1/2] ast: add function call node Johnny Richard
2024-09-27 21:11 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-25 23:20 [PATCH olang v1 2/2] parser: add support for parsing function calls Johnny Richard
2024-09-25 21:22 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-25 18:39 [PATCH olang] tests: fix diff error output Carlos Maniero
2024-09-25 18:39 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-25 18:30 [PATCH olang] parser: parse multiple function into a single translation unit Carlos Maniero
2024-09-25 18:31 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-23 22:19 [PATCH olang v1 2/3] lexer: add token comma Johnny Richard
2024-09-23 22:23 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-23 11:43 [PATCH olang 2/2] ast: permit multi declarations on translation unit Carlos Maniero
2024-09-23 11:44 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-23 10:11 [PATCH olang v1 3/3] naming: rename all identifier symbols to id Carlos Maniero
2024-09-23 10:12 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-22  0:46 [PATCH olang v2 4/4] codegen: operate mov instructions based on the symbol's type Carlos Maniero
2024-09-22  0:47 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-21 21:02 [PATCH olang v1 2/2] tests: build: add parallelization support for unit tests Johnny Richard
2024-09-21 21:05 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-21  8:25 [PATCH olang 5/5] codegen: perform mov instructions based on variable type Carlos Maniero
2024-09-21  8:26 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-21  1:13 [PATCH olang 5/5] codegen: preserve function's variable stack location Carlos Maniero
2024-09-21  1:13 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-21  0:20 [PATCH olang v1 3/3] codegen: add support scopes and symbols lookups for var Johnny Richard
2024-09-21  0:23 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-17 15:14 [PATCH olang] cli: add libc error handling Carlos Maniero
2024-09-17 15:15 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-17 13:43 [PATCH olang v1] remove unused examples programs Johnny Richard
2024-09-17 11:43 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-17 12:46 [PATCH olang v1 4/4] docs: info: add instructions to install/uninstall olang Johnny Richard
2024-09-17 10:48 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-16 16:29 [PATCH olang v1 3/3] docs: remove pandoc dependency for man docs Johnny Richard
2024-09-16 14:31 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-11  1:03 [PATCH olang v1 2/2] parser: add var definition and reference support Johnny Richard
2024-09-10 23:05 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-08-25 13:16 [PATCH olang v2 2/2] codegen: x86_64: implement binary operations Johnny Richard
2024-08-25 13:26 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-08-21  3:39 [PATCH olang 1/2] tests: add comment based integration tests mechanism Carlos Maniero
2024-08-21  3:41 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-08-13 18:55 [PATCH olang v2 2/2] ast: inline ast_node_data_t union typedef Johnny Richard
2024-08-13 18:04 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-05-12 14:30 [PATCH olang 4/4] tests: print integration tests TODOs Carlos Maniero
2024-05-12 14:31 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-04-27 12:14 [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Johnny Richard
2024-04-27 11:21 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-04-18 23:08 [PATCH olang v1] parser: fix parse expression with binop chain Johnny Richard
2024-04-18 22:11 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-04-18 22:18 [PATCH olang v1] parser: add missing <= and >= binary operators Johnny Richard
2024-04-18 21:22 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-04-18 21:58 [PATCH olang v1] docs: spec: add %, <= and >= binary operators Johnny Richard
2024-04-18 21:02 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-04-16 23:51 [PATCH olang v1] Revert "docs: spec: postpone assignment operators" Johnny Richard
2024-04-16 22:56 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-04-16 23:35 [PATCH olang v2] docs: spec: add binary expressions Johnny Richard
2024-04-16 22:40 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-04-15 18:20 [PATCH olang v1] spec: ebnf: add binary expressions Johnny Richard
2024-04-15 17:43 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-04-08  4:38 [PATCH olang v2 2/2] docs: spec: add variables and constants specification Carlos Maniero
2024-04-08  4:39 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-29  1:59 [PATCH olang] linter: turn off clang-format to keep retro compatibility with v16 Johnny Richard
2024-03-29  0:59 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-29  0:33 [PATCH olang] site: change look and feel and rewrite home introduction section Johnny Richard
2024-03-28 23:33 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-24 16:12 [PATCH olang v3] docs: create o programming language spec Johnny Richard
2024-03-24 15:16 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-19 20:18 [PATCH olang v2] docs: create o programming language spec Johnny Richard
2024-03-19 19:20 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-19 19:57 [PATCH olang v1 3/3] codegen: add compiler support to linux aarch64 arch Johnny Richard
2024-03-19 19:00 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-18  8:39 [PATCH olang v3 3/3] parser: add all binary operation expressions Johnny Richard
2024-03-18  7:43 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-17 21:29 [PATCH olang v2 3/3] parser: add all binary operation expressions Johnny Richard
2024-03-17 20:37 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-13 21:21 [PATCH olang v1 3/3] parser: add basic arithmetic expressions '+' '*' '/' '-' Johnny Richard
2024-03-13 20:29 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-13 12:44 [PATCH olang v3] refactor: rename zero programming language to olang Fabio Maciel
2024-03-13 12:45 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-12 19:35 [PATCH olang v1] refactor: rename zero programming language to olang Johnny Richard
2024-03-12 18:40 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-11  8:48 [PATCH olang] site: change dns to o-lang.org Johnny Richard
2024-03-11  7:50 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-09  0:05 [RFC PATCH olang v1] docs: create zero programming language specification Johnny Richard
2024-03-08 23:09 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-14  4:29   ` Ricardo Kagawa
2024-03-14 22:43     ` Johnny Richard
2024-03-08 23:13 [PATCH olang v1] ast: add ast_node root for the entire program Johnny Richard
2024-03-08 22:13 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-08 22:39 [PATCH olang v2 3/3] tests: add tests for the minimal possible olang program Carlos Maniero
2024-03-08 22:40 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-07 23:23 [PATCH olang 3/3] tests: add tests for the minimal possible olang program Carlos Maniero
2024-03-07 23:24 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-03-01 22:24 [PATCH olang v2 4/4] parser: create simplified parser for tiny AST Johnny Richard
2024-03-01 21:32 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-28 19:04 [PATCH olang v1 4/4] parser: create simplified parser for tiny AST Johnny Richard
2024-02-28 18:11 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-28 14:25 [PATCH olang v3] arena: optimization: ensure alignment memory access Carlos Maniero
2024-02-28 14:26 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-28 12:37 [PATCH olang v2] cli: replace memory allocation malloc -> arena Johnny Richard
2024-02-28 11:39 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-27 19:59 [PATCH olang v2 2/2] utils: create hash map data structure Johnny Richard
2024-02-27 19:01 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-24 20:40 [PATCH olang] test: fix suite name for list_test and arena_test Johnny Richard
2024-02-24 19:42 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-22 19:09 [PATCH olang] cli: replace memory allocation malloc -> arena Johnny Richard
2024-02-22 18:11 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-22 18:38 [PATCH olang] docs: add DCO information on hacking page Johnny Richard
2024-02-22 17:41 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-22 18:24 [PATCH olang] build: rename 0c.c file to main.c Johnny Richard
2024-02-22 17:26 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-21 22:20 [PATCH olang 2/2] utils: create hash map data structure Johnny Richard
2024-02-21 21:24 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-21 15:09 [PATCH olang v2] arena: optimization: make arena 8 bits aligned Carlos Maniero
2024-02-21 15:09 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-21  5:52 [PATCH olang] arena: optimization: make arena 8 bits aligned Carlos Maniero
2024-02-21  5:53 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-20 23:37 [PATCH olang] utils: add linked-list Carlos Maniero
2024-02-20 23:37 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-20 17:35 [PATCH olang v3] utils: add arena Carlos Maniero
2024-02-20 17:41 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-19 20:42 [PATCH olang v5 4/4] lexer: test: add integration tests for --dump-tokens Carlos Maniero
2024-02-19 20:48 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-19  1:44 [PATCH olang v3 2/2] lexer: create --dump-tokens cli command Johnny Richard
2024-02-19  0:47 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-18  0:50 [PATCH olang 2/2] tests: add unit tests configuration Carlos Maniero
2024-02-18  0:55 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-17 21:04 [PATCH olang] docs: deploy: replace shrt.site domain by olang.johnnyrichard.com Johnny Richard
2024-02-17 20:03 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-17 20:38 [PATCH olang] docs: build: fix docs publishing task Johnny Richard
2024-02-17 19:37 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-17 20:12 [PATCH olang] docs: add mobile version Carlos Maniero
2024-02-17 20:17 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-17 18:40 [PATCH olang v2] docs: add HACKING documentation Carlos Maniero
2024-02-17 18:45 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-17 18:29 [PATCH olang v2] docs: add white mode support Carlos Maniero
2024-02-17 18:34 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-17 17:46 [PATCH olang] docs: add white-mode support Carlos Maniero
2024-02-17 17:51 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-17 16:22 [PATCH olang] docs: add pandoc Carlos Maniero
2024-02-17 16:27 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-16 16:24 [PATCH olang v2] docs: add sphinx documentation support Johnny Richard
2024-02-16 15:26 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-16 16:23 [PATCH olang] docs: build: add deployment script Carlos Maniero
2024-02-16 16:28 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-16  8:59 [PATCH olang] docs: add sphinx documentation support Johnny Richard
2024-02-16  8:01 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-16  3:07 [PATCH olang v3 2/2] tests: add integration test setup Carlos Maniero
2024-02-16  3:12 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-02-13 20:55 [PATCH olang] docs: fix git send-email config instruction Carlos Maniero
2024-02-13 21:00 ` [olang/patches/.build.yml] build success builds.sr.ht

Code repositories for project(s) associated with this public inbox

	https://git.johnnyrichard.com/olang.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox