about summary refs log tree commit diff
path: root/lang
diff options
context:
space:
mode:
Diffstat (limited to 'lang')
-rw-r--r--lang/cpptour/README.md10
-rw-r--r--lang/cpptour/Vector-test.cc29
-rw-r--r--lang/cpptour/Vector.cc38
-rw-r--r--lang/cpptour/Vector.h12
-rw-r--r--lang/cpptour/abstract.cc19
-rw-r--r--lang/cpptour/abstract.h18
-rw-r--r--lang/cpptour/count.cc11
-rw-r--r--lang/cpptour/enumcls.cc28
-rw-r--r--lang/cpptour/helloworld.cc7
-rw-r--r--lang/cpptour/mycomplex.cc67
-rw-r--r--lang/cpptour/mycomplex.h15
-rw-r--r--lang/cpptour/myvec.cc36
-rw-r--r--lang/cpptour/square.cc21
-rw-r--r--lang/cpptour/static-ass.cc8
-rw-r--r--lang/cpptour/veccls.cc32
-rw-r--r--lang/cpptour/vecuser.cc28
-rw-r--r--lang/cpptour/weirdo.cc83
-rw-r--r--lang/mips/chapter-2/exercise-1/a.s20
-rw-r--r--lang/mips/chapter-2/exercise-1/b.s19
-rw-r--r--lang/mips/chapter-2/exercise-1/c.s15
-rw-r--r--lang/mips/chapter-2/exercise-1/d.s13
-rw-r--r--lang/mips/chapter-2/exercise-1/e.s18
-rw-r--r--lang/mips/chapter-2/exercise-1/f.s17
-rw-r--r--lang/mips/chapter-2/exercise-1/g.s19
-rw-r--r--lang/mips/chapter-2/exercise-1/h.s20
-rw-r--r--lang/mips/chapter-2/exercise-1/i.s12
-rw-r--r--lang/mips/chapter-2/exercise-1/j.s16
-rw-r--r--lang/mips/chapter-2/exercise-1/k.s28
-rw-r--r--lang/mips/chapter-2/exercise-1/l.s22
-rw-r--r--lang/mips/chapter-2/exercise-1/m.s17
-rw-r--r--lang/mips/chapter-2/exercise-1/n.s16
-rw-r--r--lang/mips/chapter-2/exercise-1/o.s17
-rw-r--r--lang/mips/chapter-2/exercise-1/p.s21
-rw-r--r--lang/mips/chapter-2/exercise-1/q.s20
-rw-r--r--lang/mips/chapter-2/exercise-1/r.s16
-rw-r--r--lang/mips/chapter-2/exercise-1/s.s16
-rw-r--r--lang/mips/chapter-2/exercise-3.s22
-rw-r--r--lang/mips/chapter-2/exercise-5.s22
-rw-r--r--lang/mips/chapter-3/exercise-10.s41
-rw-r--r--lang/mips/chapter-3/exercise-11.s41
-rw-r--r--lang/mips/chapter-3/exercise-13.s18
-rw-r--r--lang/mips/chapter-3/exercise-14.s19
-rw-r--r--lang/mips/chapter-3/exercise-15.s19
-rw-r--r--lang/mips/chapter-3/exercise-16.s19
-rw-r--r--lang/mips/chapter-3/exercise-3.s20
-rw-r--r--lang/mips/chapter-3/exercise-4.s20
-rw-r--r--lang/mips/chapter-3/exercise-6.s47
-rw-r--r--lang/mips/chapter-3/exercise-7.s47
-rw-r--r--lang/mips/mips.pdfbin0 -> 643292 bytes
-rwxr-xr-xlang/thinkraku/draft.raku298
-rwxr-xr-xlang/thinkraku/human-seconds.raku8
-rwxr-xr-xlang/thinkraku/merry-christmas.raku2
-rw-r--r--lang/zig/align.zig48
-rw-r--r--lang/zig/allowzero.zig7
-rw-r--r--lang/zig/anon-list.zig9
-rw-r--r--lang/zig/arrays.zig100
-rw-r--r--lang/zig/assign.zig25
-rw-r--r--lang/zig/blocks.zig18
-rw-r--r--lang/zig/c-string.zig12
-rw-r--r--lang/zig/comments.zig11
-rw-r--r--lang/zig/comptime-vars.zig16
-rw-r--r--lang/zig/defer.zig62
-rw-r--r--lang/zig/enum-literal.zig35
-rw-r--r--lang/zig/enums-extern.zig2
-rw-r--r--lang/zig/enums-packed.zig7
-rw-r--r--lang/zig/enums.zig86
-rw-r--r--lang/zig/errdefer.zig17
-rw-r--r--lang/zig/error-set.zig22
-rw-r--r--lang/zig/error-trace.zig44
-rw-r--r--lang/zig/error-union.zig115
-rw-r--r--lang/zig/fn.zig78
-rw-r--r--lang/zig/for.zig100
-rw-r--r--lang/zig/hello-again.zig5
-rw-r--r--lang/zig/hello.zig6
-rw-r--r--lang/zig/if.zig141
-rw-r--r--lang/zig/infer-list-literal.zig13
-rw-r--r--lang/zig/multidim.zig20
-rw-r--r--lang/zig/namespaced-global.zig15
-rw-r--r--lang/zig/noreturn.zig10
-rw-r--r--lang/zig/opaque.zig12
-rw-r--r--lang/zig/pointers.zig93
-rw-r--r--lang/zig/sentinel-terminated.zig10
-rw-r--r--lang/zig/shadow.zig10
-rw-r--r--lang/zig/slices.zig77
-rw-r--r--lang/zig/string.zig14
-rw-r--r--lang/zig/struct-anon.zig20
-rw-r--r--lang/zig/struct-default.zig11
-rw-r--r--lang/zig/struct-name.zig14
-rw-r--r--lang/zig/struct-packed.zig73
-rw-r--r--lang/zig/struct-result.zig7
-rw-r--r--lang/zig/structs.zig133
-rw-r--r--lang/zig/switch-enum-literal.zig13
-rw-r--r--lang/zig/switch-exhaust.zig9
-rw-r--r--lang/zig/switch.zig86
-rw-r--r--lang/zig/tls.zig22
-rw-r--r--lang/zig/union-anon.zig13
-rw-r--r--lang/zig/union-tag.zig68
-rw-r--r--lang/zig/union.zig15
-rw-r--r--lang/zig/unreachable.zig22
-rw-r--r--lang/zig/values.zig54
-rw-r--r--lang/zig/while-inline.zig20
-rw-r--r--lang/zig/while-unpack.zig43
-rw-r--r--lang/zig/while.zig73
103 files changed, 3383 insertions, 0 deletions
diff --git a/lang/cpptour/README.md b/lang/cpptour/README.md
new file mode 100644
index 0000000..b60cb65
--- /dev/null
+++ b/lang/cpptour/README.md
@@ -0,0 +1,10 @@
+A Tour of C++
+-------------
+
+These are my draft while following Bjarne Stroustrup tour to learn some C++11.
+Not that I eventually fell for the language, but I did realize that I simply
+cannot evite it forever. In fact, this is the preparation for a Python
+extension.
+
+Since the book is non-free (in either sense), I may not upload it. However,
+one could try to look for it in a *lib*rary. *Gen*erally it's available.
diff --git a/lang/cpptour/Vector-test.cc b/lang/cpptour/Vector-test.cc
new file mode 100644
index 0000000..fbdf129
--- /dev/null
+++ b/lang/cpptour/Vector-test.cc
@@ -0,0 +1,29 @@
+#include <cassert>
+#include <iostream>
+#include <stdexcept>
+
+#include "Vector.h"
+
+using namespace std;
+
+void
+neg_length ()
+{
+  try { Vector v (-27); }
+  catch (length_error) { cout << "it's alright" << endl; }
+  catch (bad_alloc) { cout << "BIG OOF!" << endl; }
+}
+
+void
+init ()
+{
+  Vector v {7.4, 3.2, 5.2, 6.9, 9.5, 4.2, 21.7};
+  assert(v[5] == 4.2);
+}
+
+int
+main ()
+{
+  neg_length ();
+  init ();
+}
diff --git a/lang/cpptour/Vector.cc b/lang/cpptour/Vector.cc
new file mode 100644
index 0000000..8f94345
--- /dev/null
+++ b/lang/cpptour/Vector.cc
@@ -0,0 +1,38 @@
+#include <stdexcept>
+
+#include "Vector.h"
+
+using namespace std;
+
+Vector::Vector (int s)
+{
+  if (s < 0)
+    throw length_error{"You're being negetive!"};
+  elem = new double[s];
+  sz = s;
+}
+
+Vector::Vector (initializer_list<double> lst)
+: elem {new double[lst.size()]}, sz {static_cast<int> (lst.size())}
+{
+  copy(lst.begin(), lst.end(), elem);
+}
+
+Vector::~Vector ()
+{
+  delete[] elem;
+}
+
+int
+Vector::size () noexcept
+{
+  return sz;
+}
+
+double&
+Vector::operator[] (int i)
+{
+  if (i < 0 || size() <= i)
+    throw out_of_range{"Vector::operator[]"};
+  return elem[i];
+}
diff --git a/lang/cpptour/Vector.h b/lang/cpptour/Vector.h
new file mode 100644
index 0000000..8508503
--- /dev/null
+++ b/lang/cpptour/Vector.h
@@ -0,0 +1,12 @@
+class Vector {
+public:
+  Vector (int s);
+  Vector (std::initializer_list<double>);
+  ~Vector ();
+  double& operator[] (int i);
+  int size () noexcept;
+  void push_back (double);
+private:
+  double* elem;
+  int sz;
+};
diff --git a/lang/cpptour/abstract.cc b/lang/cpptour/abstract.cc
new file mode 100644
index 0000000..f747a37
--- /dev/null
+++ b/lang/cpptour/abstract.cc
@@ -0,0 +1,19 @@
+Vector_container:Vector_container (int s) : v (s)
+{
+}
+
+Vector_container:~Vector_container ()
+{
+}
+
+double&
+Vector_container:operator[] (int i)
+{
+  return v[i];
+}
+
+int
+size () const
+{
+  return v.size ();
+}
diff --git a/lang/cpptour/abstract.h b/lang/cpptour/abstract.h
new file mode 100644
index 0000000..71191d9
--- /dev/null
+++ b/lang/cpptour/abstract.h
@@ -0,0 +1,18 @@
+#include "Vector.h"
+
+class Container {
+public:
+  virtual double& operator[] (int) = 0;
+  virtual int size () const = 0;
+  virtual ~Container () {}
+};
+
+class Vector_container : public Container {
+  Vector v;
+public:
+  Vector_container (int);
+  ~Vector_container ();
+
+  double& operator[] (int);
+  int size () const;
+};
diff --git a/lang/cpptour/count.cc b/lang/cpptour/count.cc
new file mode 100644
index 0000000..a047f04
--- /dev/null
+++ b/lang/cpptour/count.cc
@@ -0,0 +1,11 @@
+#include <iostream>
+
+using namespace std;
+
+int
+main ()
+{
+  int v[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+  for (auto& x : v)
+    cout << x << endl;
+}
diff --git a/lang/cpptour/enumcls.cc b/lang/cpptour/enumcls.cc
new file mode 100644
index 0000000..2340f65
--- /dev/null
+++ b/lang/cpptour/enumcls.cc
@@ -0,0 +1,28 @@
+#include <iostream>
+
+using namespace std;
+
+enum class Color { red, blue, green };
+enum class TraficLight { green, yellow, red };
+
+TraficLight& operator++ (TraficLight& t)
+{
+  switch (t)
+    {
+    case TraficLight::green:
+      return t = TraficLight::yellow;
+    case TraficLight::yellow:
+      return t = TraficLight::red;
+    case TraficLight::red:
+      return t = TraficLight::green;
+    }
+}
+
+int
+main ()
+{
+  Color col = Color::red;
+  TraficLight light = TraficLight::red;
+  TraficLight nxt = ++light;
+  // ugh now we test if it compiles? just wanna build some muscle memory
+}
diff --git a/lang/cpptour/helloworld.cc b/lang/cpptour/helloworld.cc
new file mode 100644
index 0000000..89a7f8a
--- /dev/null
+++ b/lang/cpptour/helloworld.cc
@@ -0,0 +1,7 @@
+#include <iostream>
+
+int
+main ()
+{
+  std::cout << "Hello, World!" << std::endl;
+}
diff --git a/lang/cpptour/mycomplex.cc b/lang/cpptour/mycomplex.cc
new file mode 100644
index 0000000..fade98f
--- /dev/null
+++ b/lang/cpptour/mycomplex.cc
@@ -0,0 +1,67 @@
+#include "mycomplex.h"
+
+constexpr double
+square (double x)
+{
+  return x * x;
+}
+
+complex&
+operator*= (complex& a, complex b)
+{
+  double r = a.real() * b.real() - a.imag() * b.imag();
+  double i = a.real() * b.imag() + a.imag() * b.real();
+  a.real(r);
+  a.imag(i);
+  return a;
+}
+
+complex&
+operator/= (complex& a, complex b)
+{
+  double d = square(b.real()) + square(b.imag());
+  complex c {b.real() / d, -b.imag() / d};
+  return a *= c;
+}
+
+complex
+operator+ (complex a, complex b)
+{
+  return a += b;
+}
+
+complex
+operator- (complex a, complex b)
+{
+  return a -= b;
+}
+
+complex
+operator- (complex a)
+{
+  return {-a.real(), -a.imag()};
+}
+
+complex
+operator* (complex a, complex b)
+{
+  return a *= b;
+}
+
+complex
+operator/ (complex a, complex b)
+{
+  return a /= b;
+}
+
+bool
+operator== (complex a, complex b)
+{
+  return a.real() == b.real() && a.imag() == b.imag();
+}
+
+bool
+operator!= (complex a, complex b)
+{
+  return !(a == b);
+}
diff --git a/lang/cpptour/mycomplex.h b/lang/cpptour/mycomplex.h
new file mode 100644
index 0000000..b7440ee
--- /dev/null
+++ b/lang/cpptour/mycomplex.h
@@ -0,0 +1,15 @@
+class complex {
+  double re, im;
+public:
+  complex (double r, double i) : re {r}, im {i} {}
+  complex (double r) : re {r}, im {0.0} {}
+  complex () : re {0.0}, im {0.0} {}
+
+  double real () const { return re; }
+  void real (double r) { re = r; }
+  double imag () const { return im; }
+  void imag (double i) { im = i; }
+
+  complex& operator+= (complex z) { re += z.re, im += z.im; return *this; }
+  complex& operator-= (complex z) { re -= z.re, im -= z.im; return *this; }
+};
diff --git a/lang/cpptour/myvec.cc b/lang/cpptour/myvec.cc
new file mode 100644
index 0000000..1314730
--- /dev/null
+++ b/lang/cpptour/myvec.cc
@@ -0,0 +1,36 @@
+#include <iostream>
+
+using namespace std;
+
+struct Vector
+{
+  int sz;       // number of elements
+  double* elem; // pointer to elements
+};
+
+void
+vector_init (Vector& v, int s)
+{
+  v.elem = new double[s];
+  v.sz = s;
+}
+
+double
+read_and_sum (int s)
+{
+  Vector v;
+  vector_init (v, s);
+  for (int i = 0; i != s; ++i)
+    cin >> v.elem[i];
+
+  double sum = 0;
+  for (int i = 0; i != s; ++i)
+    sum += v.elem[i];
+  return sum;
+}
+
+int
+main ()
+{
+  cout << read_and_sum (5) << endl;
+}
diff --git a/lang/cpptour/square.cc b/lang/cpptour/square.cc
new file mode 100644
index 0000000..fb14456
--- /dev/null
+++ b/lang/cpptour/square.cc
@@ -0,0 +1,21 @@
+#include <iostream>
+
+using namespace std;
+
+double
+square (double x)
+{
+  return x * x;
+}
+
+void
+print_square (double x)
+{
+  cout << "the quare of " << x << " is " << square (x) << endl;
+}
+
+int
+main ()
+{
+  print_square (1.234);
+}
diff --git a/lang/cpptour/static-ass.cc b/lang/cpptour/static-ass.cc
new file mode 100644
index 0000000..837a965
--- /dev/null
+++ b/lang/cpptour/static-ass.cc
@@ -0,0 +1,8 @@
+constexpr double C = 2999792.458;   // km/s
+
+int
+main ()
+{
+  constexpr double local_max = 160.0 / (60 * 60);
+  static_assert (local_max < C, "can't go that fast");
+}
diff --git a/lang/cpptour/veccls.cc b/lang/cpptour/veccls.cc
new file mode 100644
index 0000000..0162d23
--- /dev/null
+++ b/lang/cpptour/veccls.cc
@@ -0,0 +1,32 @@
+#include <iostream>
+
+using namespace std;
+
+class Vector {
+public:
+  Vector (int s) : elem {new double[s]}, sz {s} {}  // construct a Vector
+  double& operator[] (int i) { return elem[i]; }    // random access
+  int size () { return sz; }
+private:
+  double* elem; // pointer to the elements
+  int sz;       // the number of elements
+};
+
+double
+read_and_sum (int s)
+{
+  Vector v (s);
+  for (int i = 0; i != v.size (); ++i)
+    cin >> v[i];
+
+  double sum = 0;
+  for (int i = 0; i != v.size (); ++i)
+    sum += v[i];
+  return sum;
+}
+
+int
+main ()
+{
+  cout << read_and_sum (5) << endl;
+}
diff --git a/lang/cpptour/vecuser.cc b/lang/cpptour/vecuser.cc
new file mode 100644
index 0000000..0eefb0e
--- /dev/null
+++ b/lang/cpptour/vecuser.cc
@@ -0,0 +1,28 @@
+#include <cmath>
+#include <iostream>
+#include <stdexcept>
+
+#include "Vector.h"
+
+using namespace std;
+
+double
+sqrt_sum (Vector& v)
+{
+  double sum = 0;
+  for (int i = 0; i <= v.size(); ++i)
+    try { sum += sqrt(v[i]); }
+    catch (out_of_range) { cout << "Yeet!" << endl; }
+  return sum;
+}
+
+int
+main ()
+{
+  int n;
+  cin >> n;
+  Vector v (n);
+  while (n--)
+    cin >> v[n];
+  cout << sqrt_sum (v) << endl;
+}
diff --git a/lang/cpptour/weirdo.cc b/lang/cpptour/weirdo.cc
new file mode 100644
index 0000000..f79336c
--- /dev/null
+++ b/lang/cpptour/weirdo.cc
@@ -0,0 +1,83 @@
+#include <iostream>
+#include <set>
+#include <stdexcept>
+#include <string>
+#include <unordered_map>
+
+using namespace std;
+
+typedef unordered_map<char, size_t> charmap;
+typedef set<char> charset;
+
+constexpr double INF = 1e7;
+const charset VOWELS {'a', 'e', 'i', 'o', 'u'};
+
+inline size_t
+sqr (size_t i)
+{
+  return i * i;
+}
+
+bool
+isvowel (const string& s, size_t i)
+{
+  try { return VOWELS.count (s.at (i)); }
+  catch (out_of_range const& e) { return true; }
+}
+
+void
+update (const string& s, charmap& x, charmap& f)
+{
+  charset b;
+  for (const auto& c : s)
+    {
+      f[c]++;
+      b.insert (c);
+    }
+  for (const auto& c : b)
+    x[c]++;
+}
+
+int
+main ()
+{
+  size_t t, l;
+  string s;
+
+  cin >> t;
+  while (t--)
+    {
+      charmap xa, fa, xb, fb;
+      cin >> l;
+      while (l--)
+        {
+          cin >> s;
+          size_t i = s.size ();
+          bool a = true;
+
+          while (i--)
+            if (isvowel (s, i - 1) + isvowel (s, i) + isvowel (s, i + 1) < 2)
+              {
+                update (s, xb, fb);
+                a = false;
+                break;
+              }
+          if (a)
+            update (s, xa, fa);
+        }
+
+      double sc = 1.0;
+      for (const auto& p : xa)
+        sc *= p.second;
+      for (const auto& p : fa)
+        sc /= sqr (p.second);
+      for (const auto& p : xb)
+        sc /= p.second;
+      for (const auto& p : fb)
+        sc *= sqr (p.second);
+      if (sc > INF)
+        cout << "Infinity" << endl;
+      else
+        cout << sc << endl;
+    }
+}
diff --git a/lang/mips/chapter-2/exercise-1/a.s b/lang/mips/chapter-2/exercise-1/a.s
new file mode 100644
index 0000000..4da4645
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/a.s
@@ -0,0 +1,20 @@
+# t3 = t4 + t5 - t6
+	.text
+main:
+	li	$t4,	4		# t4 = 4
+	li	$t5,	5		# t5 = 5
+	li	$t6,	6		# t6 = 6
+
+	add	$t3,	$t4,	$t5	# t3 = t4 + t5
+	sub	$t3,	$t3,	$t6	# t3 -= t6
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t3		# at t3
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/b.s b/lang/mips/chapter-2/exercise-1/b.s
new file mode 100644
index 0000000..fa590b5
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/b.s
@@ -0,0 +1,19 @@
+# s3 = t2 / (s1 - 54321)
+	.text
+main:
+	li	$t2,	69		# t2 = 69
+	li	$s1,	54324		# s1 = 54324
+
+	sub	$s1,	$s1,	54321	# s1 -= 54321
+	div	$t3,	$t2,	$s1	# t3 = t2 / s1
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t3		# at a0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/c.s b/lang/mips/chapter-2/exercise-1/c.s
new file mode 100644
index 0000000..370af96
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/c.s
@@ -0,0 +1,15 @@
+# sp -= 16
+	.text
+main:
+	addi	$sp,	$sp,	-16	# sp -= 16, may underflow
+
+	li	$v0,	1		# print integer
+	move	$a0,	$sp		# at sp
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/d.s b/lang/mips/chapter-2/exercise-1/d.s
new file mode 100644
index 0000000..e20cd4c
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/d.s
@@ -0,0 +1,13 @@
+# print t3
+	.text
+main:
+	li	$v0,	1		# print integer
+	move	$a0,	$t3		# at t3
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/e.s b/lang/mips/chapter-2/exercise-1/e.s
new file mode 100644
index 0000000..d35702d
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/e.s
@@ -0,0 +1,18 @@
+# read to and echo t0
+	.text
+main:
+	li	$v0,	5		# read integer to v0
+	syscall
+
+	move	$t0,	$v0		# t0 = v0
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/f.s b/lang/mips/chapter-2/exercise-1/f.s
new file mode 100644
index 0000000..2ec14ef
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/f.s
@@ -0,0 +1,17 @@
+# a0 = array
+	.data
+array:	.word	4, 20, 6, 9
+
+	.text
+main:
+
+	li	$v0,	1		# print integer
+	la	$a0,	array		# address of array
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/g.s b/lang/mips/chapter-2/exercise-1/g.s
new file mode 100644
index 0000000..e9d8f8f
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/g.s
@@ -0,0 +1,19 @@
+# t8 = *a0
+	.data
+array:	.word	4, 20, 6, 9
+
+	.text
+main:
+	la	$a0,	array		# a0 = array
+	lw	$t8,	($a0)		# t8 = *a0
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t8		# at t8
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/h.s b/lang/mips/chapter-2/exercise-1/h.s
new file mode 100644
index 0000000..eaf63bd
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/h.s
@@ -0,0 +1,20 @@
+# a0[4] = 32768
+	.data
+array:	.word	4, 2, 0, 6, 9
+
+	.text
+main:
+	la	$a0,	array		# t0 = array
+	li	$t1,	32768		# t1 = 32768
+	sw	$t1,	16($a0)		# t0[4] = t1
+
+	li	$v0,	1		# print integer
+	lw	$a0,	16($a0)		# at t0[4]
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/i.s b/lang/mips/chapter-2/exercise-1/i.s
new file mode 100644
index 0000000..8754525
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/i.s
@@ -0,0 +1,12 @@
+# print Hello, World!
+	.data
+hello:	.asciiz "Hello, World!\n"
+
+	.text
+main:
+	li	$v0,	4		# print string
+	la	$a0,	hello		# hello
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/j.s b/lang/mips/chapter-2/exercise-1/j.s
new file mode 100644
index 0000000..95eccc7
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/j.s
@@ -0,0 +1,16 @@
+# t7 = abs(t0)
+	.text
+main:
+	li	$t0,	-420		# t0 = -420
+	abs	$t7,	$t0		# t7 = abs(t0)
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t7		# at t7
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/k.s b/lang/mips/chapter-2/exercise-1/k.s
new file mode 100644
index 0000000..60c0038
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/k.s
@@ -0,0 +1,28 @@
+# while (t0) { s1 += t0; t0 = *++t2; }
+	.data
+array:	.word	4, 2, 0, 6, 9
+
+	.text
+main:
+	la	$t2,	array		# t2 = array
+	lw	$t0,	($t2)		# t0 = *t2
+	li	$s1,	0		# s1 = 0
+
+while:
+	beqz	$t0,	end		# if (!t0) goto end
+	add	$s1,	$s1,	$t0	# s1 += t0
+	addi	$t2,	$t2,	4	# t2++
+	lw	$t0,	($t2)		# t0 = *t2
+	j	while			# goto while
+end:
+
+	li	$v0,	1		# print integer
+	move	$a0,	$s1		# at s1
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/l.s b/lang/mips/chapter-2/exercise-1/l.s
new file mode 100644
index 0000000..73b999d
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/l.s
@@ -0,0 +1,22 @@
+# for (t1 = 99; t1 > 0; v0 += t1--)
+	.text
+main:
+	li	$v0,	0		# v0 = 0
+	li	$t1,	99		# t1 = 99
+for:
+	blez	$t1,	end		# if (t1 <= 0) goto end
+	add	$v0,	$v0,	$t1	# v0 += t1
+	addi	$t1,	$t1,	-1	# t1--
+	j	for			# goto for
+end:
+
+	move	$a0,	$v0		# a0 = v0
+	li	$v0,	1		# print integer at a0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/m.s b/lang/mips/chapter-2/exercise-1/m.s
new file mode 100644
index 0000000..e02f924
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/m.s
@@ -0,0 +1,17 @@
+# t0 = 0x7fffffff - 0x80000000
+	.text
+main:
+	li	$t2,	-0x80000000	# t2 = 0x80000000
+	li	$t1,	0x7fffffff	# t1 = 0x7fffffff
+	add	$t0,	$t1,	$t2	# t0 = t1 - t2
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/n.s b/lang/mips/chapter-2/exercise-1/n.s
new file mode 100644
index 0000000..4394ebf
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/n.s
@@ -0,0 +1,16 @@
+# s0 *= -1
+	.text
+main:
+	li	$s0,	420		# s0 = 420
+	neg	$s0,	$s0		# s0 = -s0
+
+	li	$v0,	1		# print integer
+	move	$a0,	$s0		# at s0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/o.s b/lang/mips/chapter-2/exercise-1/o.s
new file mode 100644
index 0000000..06dfc5c
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/o.s
@@ -0,0 +1,17 @@
+# s1 *= a0
+	.text
+main:
+	li	$s1,	420		# s1 = 420
+	li	$a0,	69		# a0 = 69
+	mul	$s1,	$s1,	$a0	# s1 *= a0
+
+	li	$v0,	1		# print integer
+	move	$a0,	$s1		# at s1
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/p.s b/lang/mips/chapter-2/exercise-1/p.s
new file mode 100644
index 0000000..a15958f
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/p.s
@@ -0,0 +1,21 @@
+# s2 = srt(s0**2 + 56) / a3
+	.text
+main:
+	li	$s0,	420		# s0 = 420
+	li	$a3,	69		# a3 = 69
+
+	mul	$t0,	$s0,	$s0	# t0 = s0 ** 2
+	addi	$a0,	$t0,	56	# a0 = t0 + 56
+	jal	srt			# v0 = srt(a0)	# srt is undefined
+	div	$s2,	$v0,	$a3	# s2 = v0 / a3
+
+	li	$v0,	1		# print integer
+	move	$a0,	$s0		# at s2
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/q.s b/lang/mips/chapter-2/exercise-1/q.s
new file mode 100644
index 0000000..47069cd
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/q.s
@@ -0,0 +1,20 @@
+# s3 = s1 - s2 / s3
+	.text
+main:
+	li	$s1,	69		# s1 = 69
+	li	$s2,	20		# s2 = 20
+	li	$s3,	4		# s3 = 4
+
+	div	$s3,	$s2,	$s3	# s3 = s2 / s3
+	sub	$s3,	$s1,	$s3	# s3 = s1 - s3
+
+	li	$v0,	1		# print integer
+	move	$a0,	$s3		# at s3
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/r.s b/lang/mips/chapter-2/exercise-1/r.s
new file mode 100644
index 0000000..c362e64
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/r.s
@@ -0,0 +1,16 @@
+# s4 <<= 3
+	.text
+main:
+	li	$s4,	420		# s4 = 420
+	sll	$s4,	$s4,	3	# s4 <<= 3
+
+	li	$v0,	1		# print integer
+	move	$a0,	$s4		# at s4
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-1/s.s b/lang/mips/chapter-2/exercise-1/s.s
new file mode 100644
index 0000000..07c8a12
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-1/s.s
@@ -0,0 +1,16 @@
+# s5 *= pi
+	.text
+main:
+	li	$s5,	420		# s5 = 420
+	mul	$s5,	$s5,	3	# s5 *= 3
+
+	li	$v0,	1		# print integer
+	move	$a0,	$s5		# at s5
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate program run
+	syscall
diff --git a/lang/mips/chapter-2/exercise-3.s b/lang/mips/chapter-2/exercise-3.s
new file mode 100644
index 0000000..d82da72
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-3.s
@@ -0,0 +1,22 @@
+# t0 = (s1 - s0 / s2) * s4
+	.text
+main:
+	li	$s1,	4		# s1 = 4
+	li	$s0,	20		# s0 = 20
+	li	$s2,	6		# s2 = 6
+	li	$s4,	9		# s4 = 9
+
+	div	$t0,	$s0,	$s2	# t0 = s0 / s2
+	sub	$t0,	$s1,	$t0	# t0 = s1 - t0
+	mul	$t0,	$t0,	$s4	# t0 *= s4
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-2/exercise-5.s b/lang/mips/chapter-2/exercise-5.s
new file mode 100644
index 0000000..ffb4058
--- /dev/null
+++ b/lang/mips/chapter-2/exercise-5.s
@@ -0,0 +1,22 @@
+# t0 = s0/8 - s1*2 + s2
+	.text
+main:
+	li	$s0,	69		# s0 = 20
+	li	$s1,	4		# s1 = 4
+	li	$s2,	20		# s2 = 20
+
+	sra	$t0,	$s0,	3	# t0 = s0 >> 3
+	sll	$t1,	$s1,	1	# t1 = s1 << 1
+	sub	$t0,	$t0,	$t1	# t0 -= t1
+	add	$t0,	$t0,	$s2	# t0 += s2
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-10.s b/lang/mips/chapter-3/exercise-10.s
new file mode 100644
index 0000000..f3ddeef
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-10.s
@@ -0,0 +1,41 @@
+# print -35 in 8-bit two-complement binary
+	.text
+main:
+	li	$t0,	-35		# t0 = -35
+	li	$t1,	0		# t1 = 0
+	li	$t8,	8		# t8 = 8
+
+reverse:
+	beqz	$t8,	prefix		# if (!t8) goto prefix
+	andi	$t2,	$t0,	1	# t2 = t0 & 1
+	sra	$t0,	$t0,	1	# t0 >>= 1
+	sll	$t1,	$t1,	1	# t1 <<= 1
+	add	$t1,	$t1,	$t2	# t1 += t2
+	addi	$t8,	$t8,	-1	# t8--
+	j	reverse			# goto reverse
+
+prefix:
+	li	$v0,	11		# print character
+	li	$a0,	48		# 0
+	syscall
+	li	$v0,	11		# print character
+	li	$a0,	98		# b
+	syscall
+	li	$t8,	8		# t8 = 8
+
+print:
+	beqz	$t8,	end		# if (!t8) goto end
+	li	$v0,	1		# print integre
+	andi	$a0,	$t1,	1	# a0 = t1 & 1
+	syscall
+	sra	$t1,	$t1,	1	# t1 >>= 1
+	addi	$t8,	$t8,	-1	# t8--
+	j	print			# goto print
+
+end:
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-11.s b/lang/mips/chapter-3/exercise-11.s
new file mode 100644
index 0000000..f47f29f
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-11.s
@@ -0,0 +1,41 @@
+# print -32 in 8-bit two-complement binary
+	.text
+main:
+	li	$t0,	-32		# t0 = -32
+	li	$t1,	0		# t1 = 0
+	li	$t8,	8		# t8 = 8
+
+reverse:
+	beqz	$t8,	prefix		# if (!t8) goto prefix
+	andi	$t2,	$t0,	1	# t2 = t0 & 1
+	sra	$t0,	$t0,	1	# t0 >>= 1
+	sll	$t1,	$t1,	1	# t1 <<= 1
+	add	$t1,	$t1,	$t2	# t1 += t2
+	addi	$t8,	$t8,	-1	# t8--
+	j	reverse			# goto reverse
+
+prefix:
+	li	$v0,	11		# print character
+	li	$a0,	48		# 0
+	syscall
+	li	$v0,	11		# print character
+	li	$a0,	98		# b
+	syscall
+	li	$t8,	8		# t8 = 8
+
+print:
+	beqz	$t8,	end		# if (!t8) goto end
+	li	$v0,	1		# print integre
+	andi	$a0,	$t1,	1	# a0 = t1 & 1
+	syscall
+	sra	$t1,	$t1,	1	# t1 >>= 1
+	addi	$t8,	$t8,	-1	# t8--
+	j	print			# goto print
+
+end:
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-13.s b/lang/mips/chapter-3/exercise-13.s
new file mode 100644
index 0000000..6779d11
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-13.s
@@ -0,0 +1,18 @@
+# print(int('204', 8))
+	.text
+main:
+	li	$t0,	0		# t0 = 0
+	addi	$t0,	$t0,	2	# t0 += 2
+	sll	$t0,	$t0,	6	# t0 *= 8 * 8
+	addi	$t0,	$t0,	4	# t0 += 4
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-14.s b/lang/mips/chapter-3/exercise-14.s
new file mode 100644
index 0000000..b01b76b
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-14.s
@@ -0,0 +1,19 @@
+# print(int('204', 7))
+	.text
+main:
+	li	$t0,	0		# t0 = 0
+	addi	$t0,	$t0,	2	# t0 += 2
+	li	$t1,	49		# t1 = 7 * 7
+	mul	$t0,	$t0,	$t1	# t0 *= t1
+	addi	$t0,	$t0,	4	# t0 += 4
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-15.s b/lang/mips/chapter-3/exercise-15.s
new file mode 100644
index 0000000..3a16b14
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-15.s
@@ -0,0 +1,19 @@
+# print(int('204', 6))
+	.text
+main:
+	li	$t0,	0		# t0 = 0
+	addi	$t0,	$t0,	2	# t0 += 2
+	li	$t1,	36		# t1 = 6 * 6
+	mul	$t0,	$t0,	$t1	# t0 *= t1
+	addi	$t0,	$t0,	4	# t0 += 4
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-16.s b/lang/mips/chapter-3/exercise-16.s
new file mode 100644
index 0000000..1aa9dec
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-16.s
@@ -0,0 +1,19 @@
+# print(int('204', 5))
+	.text
+main:
+	li	$t0,	0		# t0 = 0
+	addi	$t0,	$t0,	2	# t0 += 2
+	li	$t1,	25		# t1 = 5 * 5
+	mul	$t0,	$t0,	$t1	# t0 *= t1
+	addi	$t0,	$t0,	4	# t0 += 4
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-3.s b/lang/mips/chapter-3/exercise-3.s
new file mode 100644
index 0000000..cb2475c
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-3.s
@@ -0,0 +1,20 @@
+# t0 = 0b10101, using only bit shift and add
+	.text
+main:
+	li	$t0,	0		# t0 = 0
+	addi	$t0,	$t0,	1	# t0++
+	sll	$t0,	$t0,	2	# t0 <<= 2
+	addi	$t0,	$t0,	1	# t0++
+	sll	$t0,	$t0,	2	# t0 <<= 2
+	addi	$t0,	$t0,	1	# t0++
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-4.s b/lang/mips/chapter-3/exercise-4.s
new file mode 100644
index 0000000..29888f1
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-4.s
@@ -0,0 +1,20 @@
+# t0 = 0b11001, using only bit shift and add
+	.text
+main:
+	li	$t0,	0		# t0 = 0
+	addi	$t0,	$t0,	1	# t0++
+	sll	$t0,	$t0,	1	# t0 <<= 1
+	addi	$t0,	$t0,	1	# t0++
+	sll	$t0,	$t0,	3	# t0 <<= 3
+	addi	$t0,	$t0,	1	# t0++
+
+	li	$v0,	1		# print integer
+	move	$a0,	$t0		# at t0
+	syscall
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-6.s b/lang/mips/chapter-3/exercise-6.s
new file mode 100644
index 0000000..8c1b6fd
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-6.s
@@ -0,0 +1,47 @@
+# print(hex(0b10101))
+	.text
+main:
+	li	$t0,	21		# t0 = 0b10101
+	li	$t1,	0		# t1 = 0
+	li	$t9,	9		# t9 = 9
+
+reverse:
+	beqz	$t0,	done		# if (!t0) goto done
+	andi	$t2,	$t0,	0xf	# t2 = t0 & 0xf
+	sra	$t0,	$t0,	4	# t0 >>= 4
+	sll	$t1,	$t1,	4	# t1 <<= 4
+	add	$t1,	$t1,	$t2	# t1 += t2
+	j	reverse			# goto reverse
+done:
+
+	li	$v0,	11		# print character
+	li	$a0,	48		# 0
+	syscall
+	li	$v0,	11		# print character
+	li	$a0,	120		# x
+	syscall
+	bnez	$t1,	print		# if (!t1) goto print
+	li	$v0,	11		# print character
+	li	$a0,	48		# 0
+	syscall
+	j	end			# goto end
+
+print:
+	beqz	$t1,	end		# if (!t1) goto end
+	andi	$t2,	$t1,	0xf	# t2 = t1 & 0xf
+	sra	$t1,	$t1,	4	# t1 >>= 4
+	addi	$a0,	$t2,	48	# a0 = chr(t2), sort of
+	ble	$t2,	$t9,	put	# if (t2 <= 9) goto put
+	addi	$a0,	$a0,	7	# a0 += 7
+put:
+	li	$v0,	11		# print character at a0
+	syscall
+	j	print			# goto print
+end:
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/chapter-3/exercise-7.s b/lang/mips/chapter-3/exercise-7.s
new file mode 100644
index 0000000..924765d
--- /dev/null
+++ b/lang/mips/chapter-3/exercise-7.s
@@ -0,0 +1,47 @@
+# print(hex(0b11001))
+	.text
+main:
+	li	$t0,	25		# t0 = 0b11001
+	li	$t1,	0		# t1 = 0
+	li	$t9,	9		# t9 = 9
+
+reverse:
+	beqz	$t0,	done		# if (!t0) goto done
+	andi	$t2,	$t0,	0xf	# t2 = t0 & 0xf
+	sra	$t0,	$t0,	4	# t0 >>= 4
+	sll	$t1,	$t1,	4	# t1 <<= 4
+	add	$t1,	$t1,	$t2	# t1 += t2
+	j	reverse			# goto reverse
+done:
+
+	li	$v0,	11		# print character
+	li	$a0,	48		# 0
+	syscall
+	li	$v0,	11		# print character
+	li	$a0,	120		# x
+	syscall
+	bnez	$t1,	print		# if (!t1) goto print
+	li	$v0,	11		# print character
+	li	$a0,	48		# 0
+	syscall
+	j	end			# goto end
+
+print:
+	beqz	$t1,	end		# if (!t1) goto end
+	andi	$t2,	$t1,	0xf	# t2 = t1 & 0xf
+	sra	$t1,	$t1,	4	# t1 >>= 4
+	addi	$a0,	$t2,	48	# a0 = chr(t2), sort of
+	ble	$t2,	$t9,	put	# if (t2 <= 9) goto put
+	addi	$a0,	$a0,	7	# a0 += 7
+put:
+	li	$v0,	11		# print character at a0
+	syscall
+	j	print			# goto print
+end:
+
+	li	$v0,	11		# print character
+	li	$a0,	10		# newline
+	syscall
+
+	li	$v0,	10		# terminate
+	syscall
diff --git a/lang/mips/mips.pdf b/lang/mips/mips.pdf
new file mode 100644
index 0000000..4a38047
--- /dev/null
+++ b/lang/mips/mips.pdf
Binary files differdiff --git a/lang/thinkraku/draft.raku b/lang/thinkraku/draft.raku
new file mode 100755
index 0000000..cfe762d
--- /dev/null
+++ b/lang/thinkraku/draft.raku
@@ -0,0 +1,298 @@
+#!/usr/bin/env raku
+# Exercise 2.2.1
+sub sphere-volume(Numeric(Cool) $r) { 4/3 * Ο€ * $rΒ³ }
+#put sphere-volume('5');
+
+# Exercise 3.1
+# Notice the operator precedence
+sub rjust(Str $str, Int $width = 70) { ' ' x $width - $str.chars ~ $str }
+#put rjust("Larry Wall", 80);
+
+# Exercise 3.2
+sub print-twice($str) {
+    put $str;
+    put $str
+}
+sub do-twice(&code, $arg) {
+    code $arg;
+    code $arg
+}
+#do-twice(&print-twice, "What's up doc");
+sub do-four(&code, $arg) { do-twice { do-twice &code, $_ }, $arg }
+
+# Exercise 3.3
+sub grid(Int $rows=2, Int $cols=2, Int $side=4) {
+    (('+' for 0..$cols).join((' ' for 0..$side).join('-'))~"\n" for 0..$rows)
+    .join((('|' for 0..$cols).join(' ' x $side*2 + 1)~"\n") x $side)
+}
+#print grid(4, 4);
+
+# Exercise 4.2
+sub check-fermat(Int $a, Int $b, Int $c, Int $n) {
+    return if $n <= 2;
+    if $a**$n + $b**$n == $c**$n {
+        put "Holy smokes, Fermat was wrong!"
+    } else {
+        put "No, that doesn't work."
+    }
+}
+
+# Exercise 4.3
+sub is-triangle($a, $b, $c) { ([-] reverse sort $a, $b, $c) < 0 }
+
+# Exercise 4.4
+sub fibonacci(Int $n, Int $a = 0, Int $b = 1) {
+    return $a if $n <= 0; #put $a;
+    fibonacci $n - 1, $b, $a + $b
+}
+#put fibonacci 20;
+
+sub hypotenuse($a, $o) { sqrt $aΒ² + $oΒ² }
+#put hypotenuse 3, 4;
+
+# Exercise 5.2
+multi ack(0, Int $n) { $n + 1 }
+multi ack(Int $m where * > 0, 0) { ack $m - 1, 1 }
+multi ack(Int $m where * > 0, Int $n where * > 0) {
+    ack $m - 1, ack($m, $n - 1)
+}
+#put ack 3, 4;
+
+# Exercise 5.3
+sub is-palindrome(Str $str) { $str eq $str.flip }
+
+# Exercise 5.4
+sub is-power-of($a, $b) { { $_ == .Int }(log $a, $b) }
+
+# Exercise 5.5: gcd is a built-in operator
+
+# Exercise 6.1
+sub my-sqrt($a, $epsilon = 0.000_000_1, $x = $a) {
+    return $x if abs $xΒ² - $a < $epsilon;
+    my-sqrt $a, $epsilon, ($x + $a/$x) / 2
+}
+
+# Exercise 6.2
+sub factorial(Int $n) { [*] 1..$n }
+sub estimate-pi {
+    my $factor = 2 * 2.sqrt / 9801;
+    sub Srinivasa-Ramanujan($k = 1, $current = 1103, $result = 1103) {
+        my $next = factorial($k * 4) * (1103 + $k*26390)
+                   / factorial($k)⁴ / 396**($k*4);
+        return $result + $next if $factor * $next < 10**-15;
+        Srinivasa-Ramanujan $k + 1, $next, $result + $next;
+    }
+    1 / $factor / Srinivasa-Ramanujan
+}
+#put abs estimate-pi() - pi;
+
+sub ducks { map * ~ 'ack' , flat('J'..'N', 'Ou', 'P', 'Qu') }
+#put ducks;
+
+sub count(Str $string, Str $substr, Int $index = 0, Int $result = 0) {
+    my $i = index $string, $substr, $index;
+    return $result unless defined $i;
+    count $string, $substr, $i + 1, $result + 1
+}
+#put count 'banana', 'na';
+
+sub bubble-sort(@seq is copy) {
+    my $done;
+    repeat {
+        $done = True;
+        for ^@seq.end -> $i {
+            if @seq[$i] > @seq[$i+1] {
+                @seq[$i, $i + 1] .= reverse
+                $done = False
+            }
+        }
+    } until $done;
+    @seq
+}
+#put bubble-sort <4 2 6 5 3 9 1>;
+
+sub select-sort(@seq is copy) {
+    for ^@seq.end -> $i {
+        for $i..@seq.end -> $j {
+            @seq[$i, $j] .= reverse if @seq[$i] > @seq[$j]
+        }
+    }
+    @seq
+}
+#put select-sort <4 2 6 5 3 9 1>;
+
+sub insert-sort(@seq is copy) {
+    for 1..@seq.end -> $i {
+        loop (my $j = $i; $j and @seq[$j] < @seq[$j - 1]; $j--) {
+            @seq[$j, $j - 1] .= reverse
+        }
+    }
+    @seq
+}
+#put insert-sort <4 2 6 5 3 9 1>;
+
+# Some simple regexes
+#put $/ if "Ο€ β‰ˆ $(Ο€)" ~~ /\d**10/;
+#put $/ if '1234567890' ~~ /^ <[0..7]>+ $/;
+#put $/ if ' Hello, World!' ~~ /\w+/;
+#put $/ if 'qaz asdf zxcv' ~~ /<< a \w*/;
+#put $/ if 'hmmm ooer' ~~ /<< <[aeiou]> \w*/;
+#put $/ if '0621323 0612345678- 0701234567' ~~ /<< 0 <[67]> \d**8 >>/;
+#put $/ if 'hMmM OoEr' ~~ /:i << <[aeiou]> \w*/;
+#put $/ if 'hmmm ooer' ~~ /(\w)$0/;
+#put $1 if 'hmmm ooer' ~~ /(\w) $0 .* ((\w) $0)/;
+
+sub YYYY-MM-DD(Str $string) {
+    "$0-$1-$2" if $string ~~ /<< (\d\d\d\d) \- (\d\d) \- (\d\d) >>
+    <?{0 < $1 < 13 && $2 && ($1 - 2 && $2 < 31 + ($1 - 1)%7%%2 ||
+                             $2 < 29 + $0%%400 + ($0%100)*($0%%4))}>/
+}
+#put YYYY-MM-DD '986-05-19-1700-02-29-1234-11-31-01-10-2000-02-29';
+
+# Exercise 7.3
+sub rotate-ascii(Str $string, Int $rotation) {
+    $string.comb.map({ m/<[A..Z]>/ && chr(65 + ($/.ord + $rotation - 65)%26) ||
+                       m/<[a..z]>/ && chr(97 + ($/.ord + $rotation - 97)%26) ||
+                       $_ }).join
+}
+#put rotate-ascii 'cheer', 7;
+#put rotate-ascii 'melon', -10;
+#put rotate-ascii 'HAL', 1;
+
+# Exercise 8.1
+#.put if .chars > 20 for '/usr/share/dict/words'.IO.lines;
+
+# Exercise 8.2
+sub words(&predicate) { '/usr/share/dict/words'.IO.lines.grep(&predicate) }
+#.put for words({ not /<[Ee]>/ });
+
+# Exercise 8.3
+multi avoids(@letters, @forbidden) { ($_ βˆ‰ @letters for @forbidden).all }
+multi avoids(Str $word, Str $forbidden) { avoids $word.comb, $forbidden.comb }
+sub least-forbidden(Int $n) {
+    my %avoids = [$_ => {} for 'a'..'z'];
+    for '/usr/share/dict/words'.IO.lines.map(~*.lc).unique -> $word {
+        %avoids{$_}{$word} = True unless defined index $word, $_ for 'a'..'z';
+    }
+
+    # Despacito (baby take it slow so we can last long)
+    [([∩] %avoids{$_}).elems => $_ for combinations('a'..'z', $n)].max.value
+}
+# Unless run on a supercomputer, there ain't no way
+# one has the patience to wait for it to finish.
+#say least-forbidden 5;
+
+# Exercise 8.4
+#.put for words { m:i/^ <[acefhlo]>+ $/ };
+
+# Exercise 8.5
+my @uses-all = <a e i o u y>;
+#.put for words { (defined index $^word, $_ for @uses-all).all };
+
+# Exercise 8.6
+sub is-abcdedarian(Str $word) { [lt] $word.lc.comb }
+#.put for words &is-abcdedarian;
+
+# Exercise 8.7
+#.put for words { m/(.) $0 (.) $1 (.) $2/ };
+
+# Exercise 8.8
+#.put if [.substr(2), substr($_ + 1, 1), substr($_ + 2, 1, 4), ~($_ + 4)]
+#        .map(&is-palindrome).all for 100_000..999_996;
+
+# Exercise 8.9
+sub age-reversible(Int $times) {
+    for '10'..'90' -> $car {
+        my $diff = $car - $car.flip;
+        my @reversible = grep { .flip == $_ - $diff }, $car..'99';
+        return @reversible if @reversible == $times
+    }
+}
+#put age-reversible(8)[*-3].flip;
+
+# Exercise 9.1
+multi nested-sum(Numeric $number) { $number }
+multi nested-sum(@array) { @array.map(&nested-sum).sum }
+#put nested-sum [1, 2, [3, 4], [5, [6, 7]], [[8], [9, [10]]]];
+
+# Exercise 9.2
+#put [\+] 1..4;
+
+# Exercise 9.5
+#put [≀] (1, 2, 2);
+#put [≀] (1, 2, 1);
+
+# Exercise 9.6
+sub is-anagram(Str $this, Str $that) { $this.comb.sort ~~ $that.comb.sort }
+#put is-anagram 'this', 'shit';
+
+# Exercise 9.7
+sub has-duplicates(@array) { @array.unique != @array }
+#put has-duplicates <o o e r>;
+
+# Exercise 9.8
+sub birthday-paradox(Int $n, Int $T) {
+    sum(map { has-duplicates map { 365.25.rand.Int }, ^$n }, ^$T) / $T
+}
+#put birthday-paradox 23, 10000;
+
+# Exercise 9.10
+sub bisect(@a, $x, Int $low = 0, Int $high = @a.elems) {
+    return unless $low < $high;
+    my $mid = ($low + $high) div 2;
+    given @a[$mid] cmp $x {
+        when Less { bisect @a, $x, $mid + 1, $high }
+        when Same { $mid }
+        when More { bisect @a, $x, $low, $mid }
+    }
+}
+
+# Exercise 9.11
+#my @words = '/usr/share/dict/words'.IO.lines;
+#put "$_ $(.flip)" if /^(.)$0*$/ ^ defined bisect @words, .flip for @words;
+
+# Exercise 9.12
+sub interlock(Str $word, @words) {
+    my ($evens, $odds);
+    for $word.comb -> $even, $odd = '' {
+        $evens ~= $even;
+        $odds ~= $odd
+    }
+    bisect(@words, $evens).defined && bisect(@words, $odds).defined
+}
+#my @words = '/usr/share/dict/words'.IO.lines;
+#.put for @words.grep:{ interlock($_, @words) };
+
+# Exercise 10.3
+sub hash-duplicates(@array) {
+    my %hash;
+    for @array {
+        return True if %hash{$_};
+        %hash{$_} = True
+    }
+    False
+}
+#put hash-duplicates <o o e r>;
+
+# Exercise 10.4
+sub rotations {
+    my %words = '/usr/share/dict/words'.IO.lines.grep(/^ <[a..z]>+ $/).Set;
+    my @result;
+    for %words.keys -> $word {
+        next unless %words{$word};
+        (%words{$word}, $_) = False, $word;
+        my $virgin = True;
+        loop (tr/a..z/b..za/; $_ cmp $word; tr/a..z/b..za/) {
+            next unless %words{$_};
+            %words{$_} = False;
+            if $virgin {
+                $virgin = False;
+                @result.push([$word, $_])
+            } else {
+                @result[*-1].push($_)
+            }
+        }
+    }
+    @result
+}
+.put for rotations;
diff --git a/lang/thinkraku/human-seconds.raku b/lang/thinkraku/human-seconds.raku
new file mode 100755
index 0000000..610213e
--- /dev/null
+++ b/lang/thinkraku/human-seconds.raku
@@ -0,0 +1,8 @@
+#!/usr/bin/env raku
+# Exercise 4.1
+sub MAIN(Int $seconds=240_000) {
+    put 'Days: ', $seconds div 86400;
+    put 'Hours: ', $seconds div 3600 % 24;
+    put 'Minutes: ', $seconds div 60 % 60;
+    put 'Seconds: ', $seconds % 60
+}
diff --git a/lang/thinkraku/merry-christmas.raku b/lang/thinkraku/merry-christmas.raku
new file mode 100755
index 0000000..654f5af
--- /dev/null
+++ b/lang/thinkraku/merry-christmas.raku
@@ -0,0 +1,2 @@
+#!/usr/bin/env raku
+sub MAIN(Str $name) { put "Merry Christmas, $name!" }
diff --git a/lang/zig/align.zig b/lang/zig/align.zig
new file mode 100644
index 0000000..b81740a
--- /dev/null
+++ b/lang/zig/align.zig
@@ -0,0 +1,48 @@
+const arch = std.Target.current.cpu.arch;
+const bytesAsSlice = std.mem.bytesAsSlice;
+const expect = std.testing.expect;
+const sliceAsBytes = std.mem.sliceAsBytes;
+const std = @import("std");
+
+test "variable alignment" {
+    var x: i32 = 1234;
+    const align_of_i32 = @alignOf(@TypeOf(x));
+    expect(@TypeOf(&x) == *i32);
+    expect(*i32 == *align(align_of_i32) i32);
+    if (arch == .x86_64)
+        expect(@typeInfo(*i32).Pointer.alignment == 4);
+}
+
+var foo: u8 align(4) = 100;
+
+test "global variable alignment" {
+    expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
+    expect(@TypeOf(&foo) == *align(4) u8);
+    const as_pointer_to_array: *[1]u8 = &foo;
+    const as_slice: []u8 = as_pointer_to_array;
+    expect(@TypeOf(as_slice) == []align(4) u8);
+}
+
+fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
+fn noop1() align(1) void {}
+fn noop4() align(4) void {}
+
+test "function alignment" {
+    expect(derp() == 1234);
+    expect(@TypeOf(noop1) == fn() align(1) void);
+    expect(@TypeOf(noop4) == fn() align(4) void);
+    noop1();
+    noop4();
+}
+
+test "pointer alignment safety" {
+    var array align(4) = [_]u32{ 0x11111111, 0x11111111 };
+    const bytes = sliceAsBytes(array[0..]);
+    expect(bar(bytes) == 0x11111111);
+}
+
+fn bar(bytes: []u8) u32 {
+    const slice4 = bytes[1..5];
+    const int_slice = bytesAsSlice(u32, @alignCast(4, slice4));
+    return int_slice[0];
+}
diff --git a/lang/zig/allowzero.zig b/lang/zig/allowzero.zig
new file mode 100644
index 0000000..39233dc
--- /dev/null
+++ b/lang/zig/allowzero.zig
@@ -0,0 +1,7 @@
+const expect = @import("std").testing.expect;
+
+test "allowzero" {
+    var zero: usize = 0;
+    var ptr = @intToPtr(*allowzero i32, zero);
+    expect(@ptrToInt(ptr) == 0);
+}
diff --git a/lang/zig/anon-list.zig b/lang/zig/anon-list.zig
new file mode 100644
index 0000000..f71bce8
--- /dev/null
+++ b/lang/zig/anon-list.zig
@@ -0,0 +1,9 @@
+const expect = @import("std").testing.expect;
+
+test "anonymous list literal syntax" {
+    var array: [4]u8 = .{11, 22, 33, 44};
+    expect(array[0] == 11);
+    expect(array[1] == 22);
+    expect(array[2] == 33);
+    expect(array[3] == 44);
+}
diff --git a/lang/zig/arrays.zig b/lang/zig/arrays.zig
new file mode 100644
index 0000000..d2658c2
--- /dev/null
+++ b/lang/zig/arrays.zig
@@ -0,0 +1,100 @@
+const expect = @import("std").testing.expect;
+const mem = @import("std").mem;
+
+// array literal
+const message = [_]u8{ 'h', 'e', 'l', 'l', 'o' };
+
+// get the size of an array
+comptime {
+    expect(message.len == 5);
+}
+
+// A string literal is a pointer to an array literal.
+const same_message = "hello";
+
+comptime {
+    expect(mem.eql(u8, &message, same_message));
+}
+
+test "iterate over an array" {
+    var sum: usize = 0;
+    for (message) |byte|
+        sum += byte;
+    expect(sum == 'h' + 'e' + 'l' * 2 + 'o');
+}
+
+// modifiable array
+var some_integers: [100]i32 = undefined;
+
+test "modify an array" {
+    for (some_integers) |*item, i|
+        item.* = @intCast(i32, i);
+    expect(some_integers[10] == 10);
+    expect(some_integers[99] == 99);
+}
+
+// array concatenation works if the values are known
+// at compile time
+const part_one = [_]i32{ 1, 2, 3, 4 };
+const part_two = [_]i32{ 5, 6, 7, 8 };
+const all_of_it = part_one ++ part_two;
+comptime {
+    expect(mem.eql(i32, &all_of_it, &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }));
+}
+
+// remember that string literals are arrays
+const hello = "hello";
+const world = "world";
+const hello_world = hello ++ " " ++ world;
+comptime {
+    expect(mem.eql(u8, hello_world, "hello world"));
+}
+
+// ** does repeating patterns
+const pattern = "ab" ** 3;
+comptime {
+    expect(mem.eql(u8, pattern, "ababab"));
+}
+
+// initialize an array to zero
+const all_zero = [_]u16{0} ** 10;
+
+comptime {
+    expect(all_zero.len == 10);
+    expect(all_zero[5] == 0);
+}
+
+// use compile-time code to initialize an array
+var fancy_array = init: {
+    var initial_value: [10]Point = undefined;
+    for (initial_value) |*pt, i| {
+        pt.* = Point{
+            .x = @intCast(i32, i),
+            .y = @intCast(i32, i) * 2,
+        };
+    }
+    break :init initial_value;
+};
+const Point = struct {
+    x: i32,
+    y: i32,
+};
+
+test "compile-time array initialization" {
+    expect(fancy_array[4].x == 4);
+    expect(fancy_array[4].y == 8);
+}
+
+// call a function to initialize an array
+var more_points = [_]Point{makePoint(3)} ** 10;
+fn makePoint(x: i32) Point {
+    return Point{
+        .x = x,
+        .y = x * 2,
+    };
+}
+test "array initialization with function calls" {
+    expect(more_points[4].x == 3);
+    expect(more_points[4].y == 6);
+    expect(more_points.len == 10);
+}
diff --git a/lang/zig/assign.zig b/lang/zig/assign.zig
new file mode 100644
index 0000000..9ce2400
--- /dev/null
+++ b/lang/zig/assign.zig
@@ -0,0 +1,25 @@
+const x = 1234;
+var b: u6 = add(10, a);
+const a = add(12, 34);
+
+fn add(l: u6, r: u6) u6 {
+    return l + r;
+}
+
+test "var" {
+    var y: u13 = 5678;
+    y += 1;
+    expect(y == 5679);
+}
+
+test "init" {
+    var z: i1 = undefined;
+    z = -1;
+}
+
+test "global" {
+    expect(a == 46);
+    expect(b == 56);
+}
+
+const expect = @import("std").testing.expect;
diff --git a/lang/zig/blocks.zig b/lang/zig/blocks.zig
new file mode 100644
index 0000000..5f6f0e8
--- /dev/null
+++ b/lang/zig/blocks.zig
@@ -0,0 +1,18 @@
+const expect = @import("std").testing.expect;
+
+test "labeled break from labeled block expression" {
+    var y: i32 = 123;
+
+    const x = blk: {
+        y += 1;
+        break :blk y;
+    };
+    expect(x == y);
+    expect(y == 124);
+}
+
+test "access variable after block scope" {
+    { var x: i32 = 1; }
+    // undeclared
+    // x += 1;
+}
diff --git a/lang/zig/c-string.zig b/lang/zig/c-string.zig
new file mode 100644
index 0000000..537fa3b
--- /dev/null
+++ b/lang/zig/c-string.zig
@@ -0,0 +1,12 @@
+const std = @import("std");
+
+// This is also available as `std.c.printf`.
+pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
+
+pub fn main() anyerror!void {
+    _ = printf("Hello, world!\n"); // OK
+
+    const msg = "Hello, world!\n";
+    const non_null_terminated_msg: [msg.len]u8 = msg.*;
+    _ = printf(&non_null_terminated_msg);
+}
diff --git a/lang/zig/comments.zig b/lang/zig/comments.zig
new file mode 100644
index 0000000..3d1c2e2
--- /dev/null
+++ b/lang/zig/comments.zig
@@ -0,0 +1,11 @@
+const expect = @import("std").testing.expect;
+
+test "comments" {
+    // Comments in Zig start with "//" and end at the next LF byte
+    // (end of line).  The below line is a comment, and won't be executed.
+
+    //expect(false);
+
+    const x = true;  // another comment
+    expect(x);
+}
diff --git a/lang/zig/comptime-vars.zig b/lang/zig/comptime-vars.zig
new file mode 100644
index 0000000..c20193d
--- /dev/null
+++ b/lang/zig/comptime-vars.zig
@@ -0,0 +1,16 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+test "comptime vars" {
+    var x: i32 = 1;
+    comptime var y: i32 = 1;
+
+    x += 1;
+    y += 1;
+
+    expect(x == 2);
+    expect(y == 2);
+
+    if (y != 2)
+        @compileError("wrong y value");
+}
diff --git a/lang/zig/defer.zig b/lang/zig/defer.zig
new file mode 100644
index 0000000..754b3af
--- /dev/null
+++ b/lang/zig/defer.zig
@@ -0,0 +1,62 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const print = std.debug.print;
+
+// defer will execute an expression at the end of the current scope.
+fn deferExample() usize {
+    var a: usize = 1;
+
+    {
+        defer a = 2;
+        a = 1;
+    }
+    expect(a == 2);
+
+    a = 5;
+    return a;
+}
+
+test "defer basics" {
+    expect(deferExample() == 5);
+}
+
+// If multiple defer statements are specified, they will be executed in
+// the reverse order they were run.
+fn deferUnwindExample() void {
+    print("\n", .{});
+
+    defer print("1 ", .{});
+    defer print("2 ", .{});
+    // defers are not run if they are never executed.
+    if (false) {
+        defer print("3 ", .{});
+    }
+    // somehow this isn't a scope though?
+    if (true) {
+        defer print("4 ", .{});
+    }
+}
+
+test "defer unwinding" {
+    deferUnwindExample();
+    print("\n", .{});
+}
+
+// The errdefer keyword is similar to defer,
+// but will only execute if the scope returns with an error.
+//
+// This is especially useful in allowing a function to clean up properly
+// on error, and replaces goto error handling tactics as seen in C.
+fn deferErrorExample(is_error: bool) !void {
+    print("\nstart of function\n", .{});
+    // This will always be executed on exit
+    defer print("end of function\n", .{});
+    errdefer print("encountered an error!\n", .{});
+    if (is_error)
+        return error.DeferError;
+}
+
+test "errdefer unwinding" {
+    deferErrorExample(false) catch {};
+    deferErrorExample(true) catch {};
+}
diff --git a/lang/zig/enum-literal.zig b/lang/zig/enum-literal.zig
new file mode 100644
index 0000000..587cfb2
--- /dev/null
+++ b/lang/zig/enum-literal.zig
@@ -0,0 +1,35 @@
+const expect = @import("std").testing.expect;
+
+const Color = enum { auto, off, on };
+
+test "enum literals" {
+    const color1: Color = .auto;
+    const color2 = Color.auto;
+    expect(color1 == color2);
+    expect(color1 == .auto);
+}
+
+test "switch using enum literals" {
+    expect(switch (Color.on) {
+        .auto => false,
+        .on => true,
+        .off => false,
+    });
+}
+
+const Number = enum(u8) { one, two, three, _ };
+
+test "switch on non-exhaustive enum" {
+    const number = Number.one;
+    expect(switch (number) {
+        .one => true,
+        .two,
+        .three => false,
+        _ => false,
+    });
+    const is_one = switch (number) {
+        .one => true,
+        else => false,
+    };
+    expect(is_one);
+}
diff --git a/lang/zig/enums-extern.zig b/lang/zig/enums-extern.zig
new file mode 100644
index 0000000..58610f1
--- /dev/null
+++ b/lang/zig/enums-extern.zig
@@ -0,0 +1,2 @@
+const Foo = extern enum { a, b, c };
+export fn entry(foo: Foo) void { }
diff --git a/lang/zig/enums-packed.zig b/lang/zig/enums-packed.zig
new file mode 100644
index 0000000..b5baaab
--- /dev/null
+++ b/lang/zig/enums-packed.zig
@@ -0,0 +1,7 @@
+const expect = @import("std").testing.expect;
+
+test "packed enum" {
+    // Warranty enum size.
+    const Number = packed enum(u2) { one, two, three };
+    expect(@sizeOf(Number) == @sizeOf(u8));
+}
diff --git a/lang/zig/enums.zig b/lang/zig/enums.zig
new file mode 100644
index 0000000..4b6a7a8
--- /dev/null
+++ b/lang/zig/enums.zig
@@ -0,0 +1,86 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const eql = std.mem.eql;
+
+// Declare an enum.
+const Type = enum { ok, not_ok };
+
+// Declare a specific instance of the enum variant.
+const c = Type.ok;
+
+test "enum ordinal value" {
+    // If you want access to the ordinal value of an enum,
+    // you can specify the tag type.
+    const Value = enum(u2) { zero, one, two };
+    const Value1 = enum { zero, one, two };
+
+    // Now you can cast between u2 and Value.
+    // The ordinal value starts from 0, counting up for each member.
+    expect(@enumToInt(Value.zero) == 0);
+    expect(@enumToInt(Value.one) == 1);
+    expect(@enumToInt(Value.two) == 2);
+
+    // Tag type needs not be explicitly specified:
+    expect(@enumToInt(Value1.zero) == 0);
+    expect(@enumToInt(Value1.one) == 1);
+    expect(@enumToInt(Value1.two) == 2);
+}
+
+// You can override the ordinal value for an enum.
+const Value2 = enum(u32) { hundred = 100, thousand = 1000, million = 1000000 };
+test "set enum ordinal value" {
+    expect(@enumToInt(Value2.hundred) == 100);
+    expect(@enumToInt(Value2.thousand) == 1000);
+    expect(@enumToInt(Value2.million) == 1000000);
+}
+
+// Enums can have methods, the same as structs and unions.
+// Enum methods are not special, they are only namespaced
+// functions that you can call with dot syntax.
+const Suit = enum {
+    clubs,
+    spades,
+    diamonds,
+    hearts,
+
+    pub fn isClubs(self: Suit) bool {
+        return self == Suit.clubs;
+    }
+};
+test "enum method" {
+    const p = Suit.spades;
+    expect(!p.isClubs());
+}
+
+// An enum variant of different types can be switched upon.
+const Foo = enum {
+    string,
+    number,
+    none,
+};
+test "enum variant switch" {
+    const p = Foo.number;
+    const what_is_it = switch (p) {
+        Foo.string => "this is a string",
+        Foo.number => "this is a number",
+        Foo.none => "this is a none",
+    };
+    expect(eql(u8, what_is_it, "this is a number"));
+}
+
+// @TagType can be used to access the integer tag type of an enum.
+const Small = enum { one, two, three, four };
+test "@TagType" {
+    expect(@TagType(Small) == u2);
+}
+
+// @typeInfo tells us the field count and the fields names:
+test "@typeInfo" {
+    expect(@typeInfo(Small).Enum.fields.len == 4);
+    expect(eql(u8, @typeInfo(Small).Enum.fields[1].name, "two"));
+}
+
+// @tagName gives a []const u8 representation of an enum value:
+test "@tagName" {
+    expect(eql(u8, @tagName(Small.three), "three"));
+}
diff --git a/lang/zig/errdefer.zig b/lang/zig/errdefer.zig
new file mode 100644
index 0000000..812b0f7
--- /dev/null
+++ b/lang/zig/errdefer.zig
@@ -0,0 +1,17 @@
+fn createFoo(param: i32) !Foo {
+    const foo = try tryToAllocateFoo();
+    // now we have allocated foo. we need to free it if the function fails.
+    // but we want to return it if the function succeeds.
+    errdefer deallocateFoo(foo);
+
+    const tmp_buf = allocateTmpBuffer() orelse return error.OutOfMemory;
+    // tmp_buf is truly a temporary resource, and we for sure want to clean it up
+    // before this block leaves scope
+    defer deallocateTmpBuffer(tmp_buf);
+
+    if (param > 1337) return error.InvalidParam;
+
+    // here the errdefer will not run since we're returning success from the function.
+    // but the defer will run!
+    return foo;
+}
diff --git a/lang/zig/error-set.zig b/lang/zig/error-set.zig
new file mode 100644
index 0000000..60b01aa
--- /dev/null
+++ b/lang/zig/error-set.zig
@@ -0,0 +1,22 @@
+const expect = @import("std").testing.expect;
+const FileOpenError = error { AccessDenied, OutOfMemory, FileNotFound };
+const AllocationError = error { OutOfMemory };
+
+fn foo(err: AllocationError) FileOpenError {
+    return err;
+}
+
+test "coerce subset to superset" {
+    const err = foo(AllocationError.OutOfMemory);
+    expect(err == FileOpenError.OutOfMemory);
+    expect(err == AllocationError.OutOfMemory);
+    expect(err == error.OutOfMemory);
+}
+
+fn bar(err: FileOpenError) AllocationError {
+    return err;
+}
+
+test "coerce superset to subset" {
+    bar(FileOpenError.OutOfMemory) catch {};
+}
diff --git a/lang/zig/error-trace.zig b/lang/zig/error-trace.zig
new file mode 100644
index 0000000..822f235
--- /dev/null
+++ b/lang/zig/error-trace.zig
@@ -0,0 +1,44 @@
+test "error return traces" {
+    try foo(12);
+}
+
+fn foo(x: i32) !void {
+    if (x >= 5) {
+        try bar();
+    } else {
+        try bang2();
+    }
+}
+
+fn bar() !void {
+    if (baz()) {
+        try quux();
+    } else |err| switch (err) {
+        error.FileNotFound => try hello(),
+        else => try another(),
+    }
+}
+
+fn baz() !void {
+    try bang1();
+}
+
+fn quux() !void {
+    try bang2();
+}
+
+fn hello() !void {
+    try bang2();
+}
+
+fn another() !void {
+    try bang1();
+}
+
+fn bang1() !void {
+    return error.FileNotFound;
+}
+
+fn bang2() !void {
+    return error.PermissionDenied;
+}
diff --git a/lang/zig/error-union.zig b/lang/zig/error-union.zig
new file mode 100644
index 0000000..8ec75b2
--- /dev/null
+++ b/lang/zig/error-union.zig
@@ -0,0 +1,115 @@
+const std = @import("std");
+const maxInt = std.math.maxInt;
+const expect = std.testing.expect;
+
+fn charToDigit(c: u8) u8 {
+    return switch (c) {
+        '0'...'9' => c - '0',
+        'A'...'Z' => c - 'A' + 10,
+        'a'...'z' => c - 'a' + 10,
+        else => maxInt(u8),
+    };
+}
+
+const ParseError = error{ InvalidChar, Overflow };
+
+pub fn parseU64(buf: []const u8, radix: u8) ParseError!u64 {
+    var x: u64 = 0;
+
+    return for (buf) |c| {
+        const digit = charToDigit(c);
+        if (digit >= radix)
+            break error.InvalidChar;
+        // x *= radix
+        if (@mulWithOverflow(u64, x, radix, &x))
+            break error.Overflow;
+        // x += digit
+        if (@addWithOverflow(u64, x, digit, &x))
+            break error.Overflow;
+    } else x;
+}
+
+test "parse u64" {
+    const result = try parseU64("1234", 10);
+    expect(result == 1234);
+}
+
+fn doAThing(str: []u8) !void {
+    const number = parseU64(str, 10) catch |err| return err;
+    // The same as
+    const number = try parseU64(str, 10);
+}
+
+test "error switch" {
+    if (parseU64("42069", 10)) |number| {
+        expect(number == 42069);
+    } else |err| switch (err) {
+        error.Overflow => {
+            // handle overflow...
+        },
+        // we promise that InvalidChar won't happen
+        // (or crash in debug mode if it does)
+        error.InvalidChar => unreachable,
+    }
+}
+
+test "error union" {
+    var foo: anyerror!i32 = undefined;
+
+    // Use compile-time reflection to access the type of an error union:
+    comptime expect(@typeInfo(@TypeOf(foo)).ErrorUnion.payload == i32);
+    comptime expect(@typeInfo(@TypeOf(foo)).ErrorUnion.error_set == anyerror);
+
+    // Coerce values
+    foo = 1234;
+    foo = error.SomeError;
+}
+
+const A = error{
+    NotDir,
+
+    /// A doc comment
+    PathNotFound,
+};
+const B = error{
+    OutOfMemory,
+
+    /// B doc comment
+    PathNotFound,
+};
+
+const C = A || B;
+
+fn bar() C!void {
+    return error.NotDir;
+}
+
+test "merge error sets" {
+    if (bar()) {
+        @panic("unexpected");
+    } else |err| switch (err) {
+        error.OutOfMemory => @panic("unexpected"),
+        error.PathNotFound => @panic("unexpected"),
+        error.NotDir => {},
+    }
+}
+
+const Error = error { Overflow };
+
+// With an inferred error set
+pub fn add_inferred(comptime T: type, a: T, b: T) !T {
+    var answer: T = undefined;
+    return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
+}
+
+// With an explicit error set
+pub fn add_explicit(comptime T: type, a: T, b: T) Error!T {
+    var answer: T = undefined;
+    return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
+}
+
+test "inferred error set" {
+    if (add_inferred(u8, 255, 1)) |_| unreachable else |err| switch (err) {
+        error.Overflow => {}, // ok
+    }
+}
diff --git a/lang/zig/fn.zig b/lang/zig/fn.zig
new file mode 100644
index 0000000..0fb3002
--- /dev/null
+++ b/lang/zig/fn.zig
@@ -0,0 +1,78 @@
+const expect = @import("std").testing.expect;
+
+// Functions are declared like this
+fn add(a: i8, b: i8) i8 {
+    return if (a == 0) b else a + b;
+}
+
+// The export specifier makes a function externally visible in the generated
+// object file, and makes it use the C ABI.
+export fn sub(a: i8, b: i8) i8 { return a - b; }
+
+// The extern specifier is used to declare a function that will be resolved
+// at link time, when linking statically, or at runtime, when linking
+// dynamically.
+extern "c" fn atan2(a: f64, b: f64) f64;
+
+// The @setCold builtin tells the optimizer that a function is rarely called.
+fn abort() noreturn {
+    @setCold(true);
+    while (true) {}
+}
+
+// The naked calling convention makes a function not have any function prologue
+// or epilogue.  This can be useful when integrating with assembly.
+fn _start() callconv(.Naked) noreturn {
+    abort();
+}
+
+// The inline specifier forces a function to be inlined at all call sites.
+// If the function cannot be inlined, it is a compile-time error.
+inline fn shiftLeftOne(a: u32) u32 {
+    return a << 1;
+}
+
+// The pub specifier allows the function to be visible when importing.
+// Another file can use @import and call sub2
+pub fn sub2(a: i8, b: i8) i8 { return a - b; }
+
+// Functions can be used as values and are equivalent to pointers.
+fn do_op(fn_call: fn (a: i8, b: i8) i8, op1: i8, op2: i8) i8 {
+    return fn_call(op1, op2);
+}
+
+test "function" {
+    expect(do_op(add, 5, 6) == 11);
+    expect(do_op(sub2, 5, 6) == -1);
+}
+
+const Point = struct { x: i32, y: i32 };
+
+fn foo(point: Point) i32 {
+    // Here, `point` could be a reference, or a copy. The function body
+    // can ignore the difference and treat it as a value. Be very careful
+    // taking the address of the parameter - it should be treated as if
+    // the address will become invalid when the function returns.
+    return point.x + point.y;
+}
+
+test "pass struct to function" {
+    expect(foo(Point{ .x = 1, .y = 2 }) == 3);
+}
+
+fn addFortyTwo(x: anytype) @TypeOf(x) {
+    return x + 42;
+}
+
+test "fn type inference" {
+    expect(addFortyTwo(1) == 43);
+    expect(@TypeOf(addFortyTwo(1)) == comptime_int);
+    const y: i64 = 2;
+    expect(addFortyTwo(y) == 44);
+    expect(@TypeOf(addFortyTwo(y)) == i64);
+}
+
+test "fn reflection" {
+    expect(@typeInfo(@TypeOf(expect)).Fn.return_type.? == void);
+    expect(@typeInfo(@TypeOf(expect)).Fn.is_var_args == false);
+}
diff --git a/lang/zig/for.zig b/lang/zig/for.zig
new file mode 100644
index 0000000..e816fcc
--- /dev/null
+++ b/lang/zig/for.zig
@@ -0,0 +1,100 @@
+const expect = @import("std").testing.expect;
+
+test "for basics" {
+    const items = [_]i32{ 4, 5, 3, 4, 0 };
+    var sum: i32 = 0;
+
+    // For loops iterate over slices and arrays.
+    for (items) |value| {
+        // Break and continue are supported.
+        if (value == 0)
+            continue;
+        sum += value;
+    }
+    expect(sum == 16);
+
+    // To iterate over a portion of a slice, reslice.
+    for (items[0..1]) |value|
+        sum += value;
+    expect(sum == 20);
+
+    // To access the index of iteration, specify a second capture value.
+    // This is zero-indexed.
+    var sum2: i32 = 0;
+    for (items) |value, i| {
+        expect(@TypeOf(i) == usize);
+        sum2 += @intCast(i32, i);
+    }
+    expect(sum2 == 10);
+}
+
+test "for reference" {
+    var items = [_]i32{ 3, 4, 2 };
+
+    // Iterate over the slice by reference by
+    // specifying that the capture value is a pointer.
+    for (items) |*value|
+        value.* += 1;
+
+    expect(items[0] == 4);
+    expect(items[1] == 5);
+    expect(items[2] == 3);
+}
+
+test "for else" {
+    // For allows an else attached to it, the same as a while loop.
+    var items = [_]?i32{ 3, 4, null, 5 };
+
+    // For loops can also be used as expressions.
+    // Similar to while loops, when you break from a for loop,
+    // the else branch is not evaluated.
+    var sum: i32 = 0;
+    const result = for (items) |value| {
+        if (value != null)
+            sum += value.?;
+    } else blk: {
+        expect(sum == 12);
+        break :blk sum;
+    };
+    expect(result == 12);
+}
+
+test "nested break" {
+    var count: usize = 0;
+    outer: for ([_]i32{ 1, 2, 3, 4, 5 }) |_| {
+        for ([_]i32{ 1, 2, 3, 4, 5 }) |_| {
+            count += 1;
+            break :outer;
+        }
+    }
+    expect(count == 1);
+}
+
+test "nested continue" {
+    var count: usize = 0;
+    outer: for ([_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }) |_| {
+        for ([_]i32{ 1, 2, 3, 4, 5 }) |_| {
+            count += 1;
+            continue :outer;
+        }
+    }
+    expect(count == 8);
+}
+
+fn typeNameLength(comptime T: type) usize {
+    return @typeName(T).len;
+}
+
+test "inline for loop" {
+    var sum: usize = 0;
+    inline for ([_]i32{ 2, 4, 6 }) |i| {
+        const T = switch (i) {
+            2 => f32,
+            4 => i8,
+            6 => bool,
+            else => unreachable,
+        };
+        sum += typeNameLength(T);
+    }
+    expect(sum == 9);
+}
diff --git a/lang/zig/hello-again.zig b/lang/zig/hello-again.zig
new file mode 100644
index 0000000..1ef4af6
--- /dev/null
+++ b/lang/zig/hello-again.zig
@@ -0,0 +1,5 @@
+const print = @import("std").debug.print;
+
+pub fn main() void {
+    print("Hello, {s}!\n", .{"world"});
+}
diff --git a/lang/zig/hello.zig b/lang/zig/hello.zig
new file mode 100644
index 0000000..56b2066
--- /dev/null
+++ b/lang/zig/hello.zig
@@ -0,0 +1,6 @@
+const std = @import("std");
+
+pub fn main() !void {
+    const stdout = std.io.getStdOut().writer();
+    try stdout.print("Hello, {}!\n", .{"world"});
+}
diff --git a/lang/zig/if.zig b/lang/zig/if.zig
new file mode 100644
index 0000000..99de2b5
--- /dev/null
+++ b/lang/zig/if.zig
@@ -0,0 +1,141 @@
+// If expressions have three uses, corresponding to the three types:
+// * bool
+// * ?T
+// * anyerror!T
+
+const expect = @import("std").testing.expect;
+
+test "if expression" {
+    // If expressions are used instead of a ternary expression.
+    const a: u32 = 5;
+    const b: u32 = 4;
+    const result = if (a != b) 47 else 3089;
+    expect(result == 47);
+}
+
+test "if boolean" {
+    // If expressions test boolean conditions.
+    const a: u32 = 5;
+    const b: u32 = 4;
+    if (a != b) {
+        expect(true);
+    } else if (a == 9) {
+        unreachable;
+    } else {
+        unreachable;
+    }
+}
+
+// If expressions test for null.
+test "if optional" {
+    if (@as(?u32, 0)) |value| {
+        expect(value == 0);
+    } else {
+        unreachable;
+    }
+
+    const b: ?u32 = null;
+    if (b) |value| {
+        unreachable;
+    } else {
+        expect(true);
+    }
+    // To test against null only, use the binary equality operator.
+    if (b == null)
+        expect(true);
+
+    // Access the value by reference using a pointer capture.
+    var c: ?u32 = 3;
+    if (c) |*value|
+        value.* = 2;
+    // The else is not required.
+    if (c) |value|
+        expect(value == 2);
+}
+
+// If expressions test for errors.  Note the |err| capture on the else.
+test "if error union" {
+    const a: anyerror!u32 = 0;
+    if (a) |value| {
+        expect(value == 0);
+    } else |err| {
+        unreachable;
+    }
+
+    const b: anyerror!u32 = error.BadValue;
+    if (b) |value| {
+        unreachable;
+    } else |err| {
+        expect(err == error.BadValue);
+    }
+
+    // The else and |err| capture is strictly required.
+    if (a) |value| {
+        expect(value == 0);
+    } else |_| {}
+
+    // To check only the error value, use an empty block expression.
+    if (b) |_| {} else |err| {
+        expect(err == error.BadValue);
+    }
+
+    // Access the value by reference using a pointer capture.
+    var c: anyerror!u32 = 3;
+    if (c) |*value| {
+        value.* = 9;
+    } else |err| {
+        unreachable;
+    }
+
+    if (c) |value| {
+        expect(value == 9);
+    } else |err| {
+        unreachable;
+    }
+}
+
+// If expressions test for errors before unwrapping optionals.
+// The |optional_value| capture's type is ?u32.
+test "if error union with optional" {
+    const a: anyerror!?u32 = 0;
+    if (a) |optional_value| {
+        expect(optional_value.? == 0);
+    } else |err| {
+        unreachable;
+    }
+
+    const b: anyerror!?u32 = null;
+    if (b) |optional_value| {
+        expect(optional_value == null);
+    } else |err| {
+        unreachable;
+    }
+    if (b) |*optional_value| {
+        if (optional_value.*) |_|
+            unreachable;
+    } else |err| {
+        unreachable;
+    }
+
+    const c: anyerror!?u32 = error.BadValue;
+    if (c) |optional_value| {
+        unreachable;
+    } else |err| {
+        expect(err == error.BadValue);
+    }
+
+    // Access the value by reference by using a pointer capture each time.
+    var d: anyerror!?u32 = 3;
+    if (d) |*optional_value| {
+        if (optional_value.*) |*value| {
+            value.* = 9;
+        }
+    } else |err| {
+        unreachable;
+    }
+    if (d) |optional_value| {
+        expect(optional_value.? == 9);
+    } else |err| {
+        unreachable;
+    }
+}
diff --git a/lang/zig/infer-list-literal.zig b/lang/zig/infer-list-literal.zig
new file mode 100644
index 0000000..ab5c770
--- /dev/null
+++ b/lang/zig/infer-list-literal.zig
@@ -0,0 +1,13 @@
+const expect = @import("std").testing.expect;
+
+test "fully anonymous list literal" {
+    dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi"});
+}
+
+fn dump(args: anytype) void {
+    expect(args.@"0" == 1234);
+    expect(args.@"1" == 12.34);
+    expect(args.@"2");
+    expect(args.@"3"[0] == 'h');
+    expect(args.@"3"[1] == 'i');
+}
diff --git a/lang/zig/multidim.zig b/lang/zig/multidim.zig
new file mode 100644
index 0000000..bf30c80
--- /dev/null
+++ b/lang/zig/multidim.zig
@@ -0,0 +1,20 @@
+const expect = @import("std").testing.expect;
+
+const mat4x4 = [4][4]f32{
+    [_]f32{ 1.0, 0.0, 0.0, 0.0 },
+    [_]f32{ 0.0, 1.0, 0.0, 1.0 },
+    [_]f32{ 0.0, 0.0, 1.0, 0.0 },
+    [_]f32{ 0.0, 0.0, 0.0, 1.0 },
+};
+
+test "multidimensional arrays" {
+    // Access the 2D array by indexing the outer array,
+    // and then the inner array.
+    expect(mat4x4[1][1] == 1.0);
+
+    // Here we iterate with for loops.
+    for (mat4x4) |row, row_index|
+        for (row) |cell, column_index|
+            if (row_index == column_index)
+                expect(cell == 1.0);
+}
diff --git a/lang/zig/namespaced-global.zig b/lang/zig/namespaced-global.zig
new file mode 100644
index 0000000..2d06ced
--- /dev/null
+++ b/lang/zig/namespaced-global.zig
@@ -0,0 +1,15 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+test "namespaced global variable" {
+    expect(foo() == 1235);
+    expect(foo() == 1236);
+}
+
+fn foo() i32 {
+    const S = struct {
+        var x: i32 = 1234;
+    };
+    S.x += 1;
+    return S.x;
+}
diff --git a/lang/zig/noreturn.zig b/lang/zig/noreturn.zig
new file mode 100644
index 0000000..6f88de1
--- /dev/null
+++ b/lang/zig/noreturn.zig
@@ -0,0 +1,10 @@
+const expect = @import("std").testing.expect;
+
+fn foo(condition: bool, b: u32) void {
+    const a = if (condition) b else return;
+    @panic("do something with a");
+}
+
+test "noreturn" {
+    foo(false, 1);
+}
diff --git a/lang/zig/opaque.zig b/lang/zig/opaque.zig
new file mode 100644
index 0000000..803d19b
--- /dev/null
+++ b/lang/zig/opaque.zig
@@ -0,0 +1,12 @@
+// Stuff for C-compat
+const Derp = opaque {};
+const Wat = opaque {};
+
+extern fn bar(d: *Derp) void;
+fn foo(w: *Wat) callconv(.C) void {
+    bar(w);
+}
+
+test "call foo" {
+    foo(undefined);
+}
diff --git a/lang/zig/pointers.zig b/lang/zig/pointers.zig
new file mode 100644
index 0000000..92c0d9d
--- /dev/null
+++ b/lang/zig/pointers.zig
@@ -0,0 +1,93 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const bytesAsSlice = std.mem.bytesAsSlice;
+
+test "address of syntax" {
+    // Get the address of a variable:
+    const x: i32 = 1234;
+    const x_ptr = &x;
+
+    // Dereference a pointer:
+    expect(x_ptr.* == 1234);
+
+    // When you get the address of a const variable,
+    // you get a const pointer to a single item.
+    expect(@TypeOf(x_ptr) == *const i32);
+
+    // If you want to mutate the value,
+    // you'd need an address of a mutable variable:
+    var y: i32 = 5678;
+    const y_ptr = &y;
+    expect(@TypeOf(y_ptr) == *i32);
+    y_ptr.* += 1;
+    expect(y_ptr.* == 5679);
+}
+
+test "pointer array access" {
+    // Taking an address of an individual element gives a
+    // pointer to a single item. This kind of pointer
+    // does not support pointer arithmetic.
+    var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+    const ptr = &array[2];
+    expect(@TypeOf(ptr) == *u8);
+
+    expect(array[2] == 3);
+    ptr.* += 1;
+    expect(array[2] == 4);
+}
+
+test "pointer slicing" {
+    var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+    const slice = array[2..4];
+    expect(slice.len == 2);
+
+    expect(array[3] == 4);
+    slice[1] += 1;
+    expect(array[3] == 5);
+}
+
+test "comptime pointers" {
+    comptime {
+        var x: i32 = 1;
+        const ptr = &x;
+        ptr.* += 1;
+        x += 1;
+        expect(ptr.* == 3);
+    }
+}
+
+test "@ptrToInt and @intToPtr" {
+    const ptr = @intToPtr(*i32, 0xdeadbee0);
+    const addr = @ptrToInt(ptr);
+    expect(@TypeOf(addr) == usize);
+    expect(addr == 0xdeadbee0);
+}
+
+test "comptime @intToPtr" {
+    comptime {
+        const ptr = @intToPtr(*i32, 0xdeadbee0);
+        const addr = @ptrToInt(ptr);
+        expect(@TypeOf(addr) == usize);
+        expect(addr == 0xdeadbee0);
+    }
+}
+
+test "volatile" {
+    const mmio_ptr = @intToPtr(*volatile u8, 0x12345678);
+    expect(@TypeOf(mmio_ptr) == *volatile u8);
+}
+
+test "pointer casting" {
+    const bytes align(@alignOf(u32)) = [_]u8{ 0x12 } ** 4;
+    const u32_ptr = @ptrCast(*const u32, &bytes);
+    expect(u32_ptr.* == 0x12121212);
+
+    // Even this example is contrived,
+    // there are better ways to do the above than pointer casting.
+    // For example, using a slice narrowing cast:
+    const u32_value = bytesAsSlice(u32, bytes[0..])[0];
+    expect(u32_value == 0x12121212);
+
+    // And even another way, the most straightforward way to do it:
+    expect(@bitCast(u32, bytes) == 0x12121212);
+}
diff --git a/lang/zig/sentinel-terminated.zig b/lang/zig/sentinel-terminated.zig
new file mode 100644
index 0000000..dd9775c
--- /dev/null
+++ b/lang/zig/sentinel-terminated.zig
@@ -0,0 +1,10 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+test "null terminated array" {
+    const array = [_:0]u8 {1, 2, 3, 4};
+
+    expect(@TypeOf(array) == [4:0]u8);
+    expect(array.len == 4);
+    expect(array[4] == 0);
+}
diff --git a/lang/zig/shadow.zig b/lang/zig/shadow.zig
new file mode 100644
index 0000000..9a37722
--- /dev/null
+++ b/lang/zig/shadow.zig
@@ -0,0 +1,10 @@
+test "separate scopes" {
+    { const pi = 3.14; }
+    { var pi: bool = true; }
+}
+
+test "inside test block" {
+    // That's right, no shadowing.
+    const pi = 3.14;
+    { var pi: i32 = 1234; }
+}
diff --git a/lang/zig/slices.zig b/lang/zig/slices.zig
new file mode 100644
index 0000000..8356c26
--- /dev/null
+++ b/lang/zig/slices.zig
@@ -0,0 +1,77 @@
+const bufPrint = std.fmt.bufPrint;
+const eql = std.mem.eql;
+const expect = std.testing.expect;
+const std = @import("std");
+
+test "basic slices" {
+    var array = [_]i32{ 1, 2, 3, 4 };
+    // A slice is a pointer and a length. The difference between an array and
+    // a slice is that the array's length is part of the type and known at
+    // compile-time, whereas the slice's length is known at runtime.
+    // Both can be accessed with the `len` field.
+    var known_at_runtime_zero: usize = 0;
+    const slice = array[known_at_runtime_zero..array.len];
+    expect(&slice[0] == &array[0]);
+    expect(slice.len == array.len);
+
+    // Using the address-of operator on a slice gives a pointer to a single
+    // item, while using the `ptr` field gives an unknown length pointer.
+    expect(@TypeOf(slice.ptr) == [*]i32);
+    expect(@TypeOf(&slice[0]) == *i32);
+    expect(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0]));
+
+    // Slices have array bounds checking. If you try to access something out
+    // of bounds, you'll get a safety check failure:
+    // slice[10] += 1;
+
+    // Note that `slice.ptr` does not invoke safety checking, while `&slice[0]`
+    // asserts that the slice has len >= 1.
+}
+
+test "using slices for strings" {
+    // Zig has no concept of strings. String literals are const pointers to
+    // arrays of u8, and by convention parameters that are "strings" are
+    // expected to be UTF-8 encoded slices of u8.
+    // Here we coerce [5]u8 to []const u8
+    const hello: []const u8 = "hello";
+    const world: []const u8 = "δΈ–η•Œ";
+
+    var all_together: [100]u8 = undefined;
+    // String concatenation example.
+    const hello_world = try bufPrint(
+        all_together[0..], "{} {}", .{ hello, world });
+
+    // Generally, you can use UTF-8 and not worry about whether something is a
+    // string. If you don't need to deal with individual characters, no need
+    // to decode.
+    expect(eql(u8, hello_world, "hello δΈ–η•Œ"));
+}
+
+test "slice pointer" {
+    var array: [10]u8 = undefined;
+    const ptr = &array;
+
+    // You can use slicing syntax to convert a pointer into a slice:
+    const slice = ptr[0..5];
+    slice[2] = 3;
+    expect(slice[2] == 3);
+    // The slice is mutable because we sliced a mutable pointer.
+    // Furthermore, it is actually a pointer to an array, since the start
+    // and end indexes were both comptime-known.
+    expect(@TypeOf(slice) == *[5]u8);
+
+    // You can also slice a slice:
+    const slice2 = slice[2..3];
+    expect(slice2.len == 1);
+    expect(slice2[0] == 3);
+}
+
+test "null terminated slice" {
+    const string = "hello";
+    const slice: [:0]const u8 = string;
+    expect(@TypeOf(string) == *const [5:0]u8);
+    expect(@TypeOf(slice) == [:0]const u8);
+
+    expect(slice.len == 5);
+    expect(slice[5] == 0);
+}
diff --git a/lang/zig/string.zig b/lang/zig/string.zig
new file mode 100644
index 0000000..af6bdc1
--- /dev/null
+++ b/lang/zig/string.zig
@@ -0,0 +1,14 @@
+const expect = @import("std").testing.expect;
+const mem = @import("std").mem;
+
+test "string literals" {
+    const bytes = "hello";
+    expect(@TypeOf(bytes) == *const [5:0]u8);
+    expect(bytes.len == 5);
+    expect(bytes[1] == 'e');
+    expect(bytes[5] == 0);
+    expect('e' == '\x65');
+    expect('\u{1f4a9}' == 128169);
+    expect('πŸ’―' == 128175);
+    expect(mem.eql(u8, "hello", "h\x65llo"));
+}
diff --git a/lang/zig/struct-anon.zig b/lang/zig/struct-anon.zig
new file mode 100644
index 0000000..a666bd0
--- /dev/null
+++ b/lang/zig/struct-anon.zig
@@ -0,0 +1,20 @@
+const expect = @import("std").testing.expect;
+
+test "fully anonymous struct" {
+    dump(.{
+        .int = @as(u32, 1234),
+        .float = @as(f64, 12.34),
+        .b = true,
+        .s = "hi",
+    });
+}
+
+fn dump(args: anytype) void {
+    expect(args.int == 1234);
+    expect(args.float == 12.34);
+    expect(args.b);
+    expect(args.s[0] == 'h');
+    expect(args.s[1] == 'i');
+    // Type is well infered, i.e. the following fail at comp time:
+    // expect(args.a);
+}
diff --git a/lang/zig/struct-default.zig b/lang/zig/struct-default.zig
new file mode 100644
index 0000000..941d201
--- /dev/null
+++ b/lang/zig/struct-default.zig
@@ -0,0 +1,11 @@
+const expect = @import("std").testing.expect;
+
+const Foo = struct {
+    a: i32 = 1234,
+    b: i32,
+};
+
+test "default struct initialization fields" {
+    const x = Foo{ .b = 5 };
+    expect(x.a + x.b == 1239);
+}
diff --git a/lang/zig/struct-name.zig b/lang/zig/struct-name.zig
new file mode 100644
index 0000000..8c3affc
--- /dev/null
+++ b/lang/zig/struct-name.zig
@@ -0,0 +1,14 @@
+const print = @import("std").debug.print;
+
+pub fn main() void {
+    const Foo = struct {};
+    print("variable: {}\n", .{@typeName(Foo)});
+    print("anonymous: {}\n", .{@typeName(struct {})});
+    print("function: {}\n", .{@typeName(List(i32))});
+}
+
+fn List(comptime T: type) type {
+    return struct {
+        x: T,
+    };
+}
diff --git a/lang/zig/struct-packed.zig b/lang/zig/struct-packed.zig
new file mode 100644
index 0000000..f493661
--- /dev/null
+++ b/lang/zig/struct-packed.zig
@@ -0,0 +1,73 @@
+const std = @import("std");
+const endian = std.builtin.endian;
+const expect = std.testing.expect;
+
+const Full = packed struct {
+    number: u16,
+};
+const Divided = packed struct {
+    half1: u8,
+    quarter3: u4,
+    quarter4: u4,
+};
+
+fn doTheTest() void {
+    expect(@sizeOf(Full) == 2);
+    expect(@sizeOf(Divided) == 2);
+    var full = Full{ .number = 0x1234 };
+    var divided = @bitCast(Divided, full);
+    switch (endian) {
+        .Big => {
+            expect(divided.half1 == 0x12);
+            expect(divided.quarter3 == 0x3);
+            expect(divided.quarter4 == 0x4);
+        },
+        .Little => {
+            expect(divided.half1 == 0x34);
+            expect(divided.quarter3 == 0x2);
+            expect(divided.quarter4 == 0x1);
+        },
+    }
+}
+
+test "@bitCast between packed structs" {
+    doTheTest();
+    comptime doTheTest();
+}
+
+const BitField = packed struct {
+    a: u3,
+    b: u3,
+    c: u2,
+};
+
+var foo = BitField{
+    .a = 1,
+    .b = 2,
+    .c = 3,
+};
+
+fn bar(x: *const u3) u3 {
+    return x.*;
+}
+
+test "pointer to non-byte-aligned field" {
+    const ptr = &foo.b;
+    expect(ptr.* == 2);
+    // The pointer to a non-byte-aligned field has special properties
+    // and cannot be passed when a normal pointer is expected:
+    // expect(bar(ptr) == 2);
+    // Here's why:
+    expect(@ptrToInt(&foo.a) == @ptrToInt(&foo.b));
+    expect(@ptrToInt(&foo.a) == @ptrToInt(&foo.c));
+
+    comptime {
+        expect(@bitOffsetOf(BitField, "a") == 0);
+        expect(@bitOffsetOf(BitField, "b") == 3);
+        expect(@bitOffsetOf(BitField, "c") == 6);
+
+        expect(@byteOffsetOf(BitField, "a") == 0);
+        expect(@byteOffsetOf(BitField, "b") == 0);
+        expect(@byteOffsetOf(BitField, "c") == 0);
+    }
+}
diff --git a/lang/zig/struct-result.zig b/lang/zig/struct-result.zig
new file mode 100644
index 0000000..fcd556a
--- /dev/null
+++ b/lang/zig/struct-result.zig
@@ -0,0 +1,7 @@
+const expect = @import("std").testing.expect;
+const Point = struct { x: i32, y: i32 };
+
+test "anonymous struct literal" {
+    const pt: Point = .{ .x = 13, .y = 67 };
+    expect(pt.x + pt.y == 80);
+}
diff --git a/lang/zig/structs.zig b/lang/zig/structs.zig
new file mode 100644
index 0000000..d90f4ff
--- /dev/null
+++ b/lang/zig/structs.zig
@@ -0,0 +1,133 @@
+// Declare a struct.
+// Zig gives no guarantees about the order of fields and the size of
+// the struct but the fields are guaranteed to be ABI-aligned.
+const Point = struct {
+    x: f32,
+    y: f32,
+};
+
+// Maybe we want to pass it to OpenGL so we want to be particular about
+// how the bytes are arranged.
+const Point2 = packed struct {
+    x: f32,
+    y: f32,
+};
+
+// Declare an instance of a struct.
+const p = Point {
+    .x = 0.12,
+    .y = 0.34,
+};
+
+// Maybe we're not ready to fill out some of the fields.
+var p2 = Point {
+    .x = 0.12,
+    .y = undefined,
+};
+
+// Structs can have methods
+// Struct methods are not special, they are only namespaced
+// functions that you can call with dot syntax.
+const Vec3 = struct {
+    x: f32,
+    y: f32,
+    z: f32,
+
+    pub fn init(x: f32, y: f32, z: f32) Vec3 {
+        return Vec3 {
+            .x = x,
+            .y = y,
+            .z = z,
+        };
+    }
+
+    pub fn dot(self: Vec3, other: Vec3) f32 {
+        return self.x * other.x + self.y * other.y + self.z * other.z;
+    }
+};
+
+const expect = @import("std").testing.expect;
+test "dot product" {
+    const v1 = Vec3.init(1.0, 0.0, 0.0);
+    const v2 = Vec3.init(0.0, 1.0, 0.0);
+    expect(v1.dot(v2) == 0.0);
+
+    // Other than being available to call with dot syntax, struct methods are
+    // not special. You can reference them as any other declaration inside
+    // the struct:
+    expect(Vec3.dot(v1, v2) == 0.0);
+}
+
+// Structs can have global declarations.
+// Structs can have 0 fields.
+const Empty = struct {
+    pub const PI = 3.14;
+};
+test "struct namespaced variable" {
+    expect(Empty.PI == 3.14);
+    expect(@sizeOf(Empty) == 0);
+
+    // you can still instantiate an empty struct
+    const does_nothing = Empty {};
+}
+
+// struct field order is determined by the compiler for optimal performance.
+// however, you can still calculate a struct base pointer given a field pointer:
+fn setYBasedOnX(x: *f32, y: f32) void {
+    const point = @fieldParentPtr(Point, "x", x);
+    point.y = y;
+}
+test "field parent pointer" {
+    var point = Point {
+        .x = 0.1234,
+        .y = 0.5678,
+    };
+    setYBasedOnX(&point.x, 0.9);
+    expect(point.y == 0.9);
+}
+
+// You can return a struct from a function.
+// This is how we do generics in Zig:
+fn LinkedList(comptime T: type) type {
+    return struct {
+        pub const Node = struct {
+            prev: ?*Node,
+            next: ?*Node,
+            data: T,
+        };
+
+        first: ?*Node,
+        last:  ?*Node,
+        len:   usize,
+    };
+}
+
+test "linked list" {
+    // Functions called at compile-time are memoized.
+    // This means you can do this:
+    expect(LinkedList(i32) == LinkedList(i32));
+
+    var list = LinkedList(i32) {
+        .first = null,
+        .last = null,
+        .len = 0,
+    };
+    expect(list.len == 0);
+
+    // Since types are first class values you can instantiate the type
+    // by assigning it to a variable:
+    const ListOfInts = LinkedList(i32);
+    expect(ListOfInts == LinkedList(i32));
+
+    var node = ListOfInts.Node {
+        .prev = null,
+        .next = null,
+        .data = 1234,
+    };
+    var list2 = LinkedList(i32) {
+        .first = &node,
+        .last = &node,
+        .len = 1,
+    };
+    expect(list2.first.?.data == 1234);
+}
diff --git a/lang/zig/switch-enum-literal.zig b/lang/zig/switch-enum-literal.zig
new file mode 100644
index 0000000..550de93
--- /dev/null
+++ b/lang/zig/switch-enum-literal.zig
@@ -0,0 +1,13 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+const Color = enum { auto, off, on };
+
+test "enum literals with switch" {
+    const color = Color.off;
+    const result = switch (color) {
+        .auto, .on => false,
+        .off => true,
+    };
+    expect(result);
+}
diff --git a/lang/zig/switch-exhaust.zig b/lang/zig/switch-exhaust.zig
new file mode 100644
index 0000000..4777f19
--- /dev/null
+++ b/lang/zig/switch-exhaust.zig
@@ -0,0 +1,9 @@
+const Color = enum { auto, off, on };
+
+test "exhaustive switching" {
+    const color = Color.off;
+    switch (color) {
+        Color.auto => {},
+        Color.on => {},
+    }
+}
diff --git a/lang/zig/switch.zig b/lang/zig/switch.zig
new file mode 100644
index 0000000..7fd3da5
--- /dev/null
+++ b/lang/zig/switch.zig
@@ -0,0 +1,86 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const os = std.Target.current.os.tag;
+
+test "switch simple" {
+    const a: u64 = 10;
+    const zz: u64 = 103;
+
+    // All branches of a switch expression must be able to be coerced
+    // to a common type.  Branches cannot fallthrough. If fallthrough behavior
+    // is desired, combine the cases and use an if.
+    const b = switch (a) {
+        // Multiple cases can be combined via a ','
+        1, 2, 3 => 0,
+
+        // Ranges can be specified using the ... syntax.
+        // These are inclusive both ends.
+        5...100 => 1,
+
+        // Branches can be arbitrarily complex.
+        101 => blk: {
+            const c: u64 = 5;
+            break :blk c * 2 + 1;
+        },
+
+        // Switching on arbitrary expressions is allowed as long as the
+        // expression is known at compile-time.
+        zz => zz,
+        blk: {
+            const d: u32 = 5;
+            const e: u32 = 100;
+            break :blk d + e;
+        } => 107,
+
+        // The else branch catches everything not already captured.
+        // Else branches are mandatory unless the entire range of values
+        // is handled.
+        else => 9,
+    };
+
+    expect(b == 1);
+}
+
+// Switch expressions can be used outside a function:
+const os_msg = switch (os) {
+    .linux => "we found a linux user",
+    else => "not a linux user",
+};
+
+// Inside a function, switch statements implicitly are compile-time
+// evaluated if the target expression is compile-time known.
+test "switch inside function" {
+    switch (os) {
+        // On an OS other than fuchsia, block is not even analyzed,
+        // so this compile error is not triggered.
+        // On fuchsia this compile error would be triggered.
+        .fuchsia => @compileError("fuchsia not supported"),
+        else => {},
+    }
+}
+
+test "switch on tagged union" {
+    const Point = struct { x: u8, y: u8 };
+    const Item = union(enum) { a: u32, c: Point, d, e: u32 };
+    var a = Item{ .c = Point{ .x = 1, .y = 2 } };
+
+    // Switching on more complex enums is allowed.
+    const b = switch (a) {
+        // A capture group is allowed on a match, and will return the enum
+        // value matched.  If the payload types of both cases are the same
+        // they can be put into the same switch prong.
+        Item.a, Item.e => |item| item,
+
+        // A reference to the matched value can be obtained using `*` syntax.
+        Item.c => |*item| blk: {
+            item.*.x += 1;
+            break :blk 6;
+        },
+
+        // No else is required if the types cases was exhaustively handled
+        Item.d => 8,
+    };
+
+    expect(b == 6);
+    expect(a.c.x == 2);
+}
diff --git a/lang/zig/tls.zig b/lang/zig/tls.zig
new file mode 100644
index 0000000..b47b17c
--- /dev/null
+++ b/lang/zig/tls.zig
@@ -0,0 +1,22 @@
+const assert = std.debug.assert;
+const std = @import("std");
+const spawn = std.Thread.spawn;
+
+threadlocal var x: i32 = 1234;
+
+test "thread local storage" {
+    const thread1 = try spawn({}, testTls);
+    defer thread1.wait();
+
+    const thread2 = try spawn({}, testTls);
+    defer thread2.wait();
+
+    // Main thread
+    testTls({});
+}
+
+fn testTls(context: void) void {
+    assert(x == 1234);
+    x += 1;
+    assert(x == 1235);
+}
diff --git a/lang/zig/union-anon.zig b/lang/zig/union-anon.zig
new file mode 100644
index 0000000..d26dcae
--- /dev/null
+++ b/lang/zig/union-anon.zig
@@ -0,0 +1,13 @@
+const expect = @import("std").testing.expect;
+const Number = union { int: i32, float: f64 };
+
+fn makeNumber() Number {
+    return .{.float = 12.34};
+}
+
+test "anonymous union literal syntax" {
+    var i: Number = .{.int = 42};
+    var f = makeNumber();
+    expect(i.int == 42);
+    expect(f.float == 12.34);
+}
diff --git a/lang/zig/union-tag.zig b/lang/zig/union-tag.zig
new file mode 100644
index 0000000..6954c73
--- /dev/null
+++ b/lang/zig/union-tag.zig
@@ -0,0 +1,68 @@
+const eql = std.mem.eql;
+const expect = std.testing.expect;
+const std = @import("std");
+
+const ComplexTypeTag = enum { ok, not_ok };
+const ComplexType = union(ComplexTypeTag) { ok: u8, not_ok: void };
+
+test "switch on tagged union" {
+    const c = ComplexType{ .ok = 42 };
+    expect(@as(ComplexTypeTag, c) == ComplexTypeTag.ok);
+
+    switch (c) {
+        ComplexTypeTag.ok => |value| expect(value == 42),
+        ComplexTypeTag.not_ok => unreachable,
+    }
+}
+
+test "@TagType" {
+    expect(@TagType(ComplexType) == ComplexTypeTag);
+}
+
+test "coerce to enum" {
+    const c1: ComplexType = ComplexType{ .ok = 42 };
+    const c2: ComplexTypeTag = ComplexType.not_ok;
+    expect(c1 == .ok);
+    expect(c2 == .not_ok);
+}
+
+test "modify tagged union in switch" {
+    var c = ComplexType{ .ok = 42 };
+    expect(c == .ok);
+
+    switch (c) {
+        ComplexTypeTag.ok => |*value| value.* += 1,
+        ComplexTypeTag.not_ok => unreachable,
+    }
+
+    expect(c.ok == 43);
+}
+
+const Variant = union(enum) {
+    int: i32,
+    boolean: bool,
+
+    // void can be omitted when inferring enum tag type.
+    none,
+
+    fn truthy(self: Variant) bool {
+        return switch (self) {
+            Variant.int => |x_int| x_int != 0,
+            Variant.boolean => |x_bool| x_bool,
+            Variant.none => false,
+        };
+    }
+};
+
+test "union method" {
+    var v1 = Variant{ .int = 420 };
+    var v2 = Variant{ .boolean = false };
+
+    expect(v1.truthy());
+    expect(!v2.truthy());
+}
+
+const Small2 = union(enum) { a: i32, b: bool, c: u8 };
+test "@tagName" {
+    expect(eql(u8, @tagName(Small2.a), "a"));
+}
diff --git a/lang/zig/union.zig b/lang/zig/union.zig
new file mode 100644
index 0000000..a9445fd
--- /dev/null
+++ b/lang/zig/union.zig
@@ -0,0 +1,15 @@
+const expect = @import("std").testing.expect;
+const Payload = union {
+    int: i64,
+    float: f64,
+    boolean: bool,
+};
+
+test "simple union" {
+    var payload = Payload{ .int = 1234 };
+    expect(payload.int == 1234);
+    // Nope this is not how it works.
+    // payload.float = 12.34;
+    payload = Payload{ .float = 12.34 };
+    expect(payload.float == 12.34);
+}
diff --git a/lang/zig/unreachable.zig b/lang/zig/unreachable.zig
new file mode 100644
index 0000000..26463a9
--- /dev/null
+++ b/lang/zig/unreachable.zig
@@ -0,0 +1,22 @@
+test "basic math" {
+    const x = 1;
+    const y = 2;
+    if (x + y != 3)
+        unreachable;
+}
+
+fn assert(ok: bool) void {
+    if (!ok) unreachable; // assertion failure
+}
+
+// This test will fail because we hit unreachable.
+test "this will fail" {
+    assert(false);
+}
+
+// The type of unreachable is noreturn.
+test "type of unreachable" {
+    // However this assertion will still fail because
+    // evaluating unreachable at compile-time is a compile error.
+    comptime assert(@TypeOf(unreachable) == noreturn);
+}
diff --git a/lang/zig/values.zig b/lang/zig/values.zig
new file mode 100644
index 0000000..4095da5
--- /dev/null
+++ b/lang/zig/values.zig
@@ -0,0 +1,54 @@
+// Top-level declarations are order-independent:
+const print = std.debug.print;
+const std = @import("std");
+const os = std.os;
+const assert = std.debug.assert;
+
+pub fn main() void {
+    // integers
+    const one_plus_one: i32 = 1 + 1;
+    print("1 + 1 = {}\n", .{one_plus_one});
+
+    // floats
+    const seven_div_three: f32 = 7.0 / 3.0;
+    print("7.0 / 3.0 = {}\n", .{seven_div_three});
+
+    // boolean
+    print("{}\n{}\n{}\n", .{
+        true and false,
+        true or false,
+        !true,
+    });
+
+    // optional
+    var optional_value: ?[]const u8 = null;
+    assert(optional_value == null);
+
+    print("\noptional 1\ntype: {}\nvalue: {}\n", .{
+        @typeName(@TypeOf(optional_value)),
+        optional_value,
+    });
+
+    optional_value = "hi";
+    assert(optional_value != null);
+
+    print("\noptional 2\ntype: {}\nvalue: {}\n", .{
+        @typeName(@TypeOf(optional_value)),
+        optional_value,
+    });
+
+    // error union
+    var number_or_error: anyerror!i32 = error.ArgNotFound;
+
+    print("\nerror union 1\ntype: {}\nvalue: {}\n", .{
+        @typeName(@TypeOf(number_or_error)),
+        number_or_error,
+    });
+
+    number_or_error = 1234;
+
+    print("\nerror union 2\ntype: {}\nvalue: {}\n", .{
+        @typeName(@TypeOf(number_or_error)),
+        number_or_error,
+    });
+}
diff --git a/lang/zig/while-inline.zig b/lang/zig/while-inline.zig
new file mode 100644
index 0000000..2af1160
--- /dev/null
+++ b/lang/zig/while-inline.zig
@@ -0,0 +1,20 @@
+const expect = @import("std").testing.expect;
+
+fn typeNameLength(comptime T: type) usize {
+    return @typeName(T).len;
+}
+
+test "inline while loop" {
+    comptime var i = 0;
+    var sum: usize = 0;
+    inline while (i < 3) : (i += 1) {
+        const T = switch (i) {
+            0 => f32,
+            1 => i8,
+            2 => bool,
+            else => unreachable,
+        };
+        sum += typeNameLength(T);
+    }
+    expect(sum == 9);
+}
diff --git a/lang/zig/while-unpack.zig b/lang/zig/while-unpack.zig
new file mode 100644
index 0000000..d10c385
--- /dev/null
+++ b/lang/zig/while-unpack.zig
@@ -0,0 +1,43 @@
+const expect = @import("std").testing.expect;
+
+var numbers_left: u32 = undefined;
+
+fn eventuallyNullSequence() ?u32 {
+    return if (numbers_left == 0) null else blk: {
+        numbers_left -= 1;
+        break :blk numbers_left;
+    };
+}
+
+fn eventuallyErrorSequence() anyerror!u32 {
+    return if (numbers_left == 0) error.ReachedZero else blk: {
+        numbers_left -= 1;
+        break :blk numbers_left;
+    };
+}
+
+test "while null capture" {
+    var sum1: u32 = 0;
+    numbers_left = 3;
+    while (eventuallyNullSequence()) |value|
+        sum1 += value;
+    expect(sum1 == 3);
+
+    var sum2: u32 = 0;
+    numbers_left = 3;
+    while (eventuallyNullSequence()) |value| {
+        sum2 += value;
+    } else {
+        expect(sum2 == 3);
+    }
+}
+
+test "while error union capture" {
+    var sum: u32 = 0;
+    numbers_left = 3;
+    while (eventuallyErrorSequence()) |value| {
+        sum += value;
+    } else |err| {
+        expect(err == error.ReachedZero);
+    }
+}
diff --git a/lang/zig/while.zig b/lang/zig/while.zig
new file mode 100644
index 0000000..9fe87e9
--- /dev/null
+++ b/lang/zig/while.zig
@@ -0,0 +1,73 @@
+const expect = @import("std").testing.expect;
+
+test "while basic" {
+    var i: usize = 0;
+    while (i < 10)
+        i += 1;
+    expect(i == 10);
+}
+
+test "while break" {
+    var i: usize = 0;
+    while (true) {
+        if (i == 10)
+            break;
+        i += 1;
+    }
+    expect(i == 10);
+}
+
+test "while continue" {
+    var i: usize = 0;
+    while (true) {
+        i += 1;
+        if (i < 10)
+            continue;
+        break;
+    }
+    expect(i == 10);
+}
+
+test "while loop continue expression" {
+    var i: usize = 0;
+    while (i < 10) : (i += 1) {}
+    expect(i == 10);
+}
+
+test "while loop continue expression, more complicated" {
+    var i: usize = 1;
+    var j: usize = 1;
+    while (i * j < 2000) : ({ i *= 2; j *= 3; })
+        expect(i * j < 2000);
+}
+
+test "while else" {
+    expect(rangeHasNumber(0, 10, 5));
+    expect(!rangeHasNumber(0, 10, 15));
+}
+
+fn rangeHasNumber(begin: usize, end: usize, number: usize) bool {
+    var i = begin;
+    return while (i < end) : (i += 1) {
+        if (i == number) {
+            break true;
+        }
+    } else false;
+}
+
+test "nested break" {
+    outer: while (true) {
+        while (true) {
+            break :outer;
+        }
+    }
+}
+
+test "nested continue" {
+    var i: usize = 0;
+    outer: while (i < 10) : (i += 1) {
+        while (true) {
+            continue :outer;
+        }
+    }
+}