diff options
Diffstat (limited to 'lang')
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; + } + } +} |