Created
December 30, 2022 19:50
-
-
Save nikki93/458852c50cd4822f2c9935ce0d41a2bc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string.h> | |
#include "rect.hh" | |
#include "sum_fields.hh" | |
#include "person/person.hh" | |
#include "gx.hh" | |
// | |
// Types | |
// | |
struct Point; | |
struct Before; | |
struct Inner; | |
struct Outer; | |
struct PtrPtr; | |
template<typename T> | |
struct Holder; | |
struct HasArray; | |
template<typename T> | |
using Seq = gx::Slice<T>; | |
struct SingleIncr; | |
struct DoubleIncr; | |
using Enum = int; | |
struct Nums; | |
struct HasDefaults; | |
struct HasString; | |
struct Foo; | |
struct Bar; | |
struct Point { | |
float x; | |
float y; | |
}; | |
struct Before { | |
Point p; | |
}; | |
struct Inner { | |
int z; | |
}; | |
struct Outer { | |
int x; | |
int y; | |
Inner inner; | |
}; | |
struct PtrPtr { | |
int **pp; | |
}; | |
template<typename T> | |
struct Holder { | |
T Item; | |
}; | |
struct HasArray { | |
gx::Array<int, 4> arr; | |
}; | |
struct SingleIncr { | |
int val; | |
}; | |
struct DoubleIncr { | |
int val; | |
}; | |
struct Nums { | |
int A; | |
int B; | |
int C; | |
int D; | |
}; | |
struct HasDefaults { | |
int foo = 42; | |
float bar = 6.4; | |
Point point = { 1, 2 }; | |
}; | |
struct HasString { | |
gx::String s; | |
}; | |
struct Foo { | |
int val; | |
}; | |
struct Bar { | |
int X; | |
int Y; | |
}; | |
// | |
// Meta | |
// | |
inline void forEachField(Point &val, auto &&func) { | |
} | |
inline void forEachField(Before &val, auto &&func) { | |
} | |
inline void forEachField(Inner &val, auto &&func) { | |
} | |
inline void forEachField(Outer &val, auto &&func) { | |
} | |
inline void forEachField(PtrPtr &val, auto &&func) { | |
} | |
template<typename T> | |
struct gx::FieldTag<Holder<T>, 0> { | |
inline static constexpr gx::FieldAttribs attribs { .name = "item" }; | |
}; | |
template<typename T> | |
inline void forEachField(Holder<T> &val, auto &&func) { | |
func(gx::FieldTag<Holder<T>, 0>(), val.Item); | |
} | |
inline void forEachField(HasArray &val, auto &&func) { | |
} | |
inline void forEachField(SingleIncr &val, auto &&func) { | |
} | |
inline void forEachField(DoubleIncr &val, auto &&func) { | |
} | |
template<> | |
struct gx::FieldTag<Nums, 0> { | |
inline static constexpr gx::FieldAttribs attribs { .name = "a" }; | |
}; | |
template<> | |
struct gx::FieldTag<Nums, 1> { | |
inline static constexpr gx::FieldAttribs attribs { .name = "b" }; | |
}; | |
template<> | |
struct gx::FieldTag<Nums, 2> { | |
inline static constexpr gx::FieldAttribs attribs { .name = "c" }; | |
}; | |
template<> | |
struct gx::FieldTag<Nums, 3> { | |
inline static constexpr gx::FieldAttribs attribs { .name = "d", .twice = true }; | |
}; | |
inline void forEachField(Nums &val, auto &&func) { | |
func(gx::FieldTag<Nums, 0>(), val.A); | |
func(gx::FieldTag<Nums, 1>(), val.B); | |
func(gx::FieldTag<Nums, 2>(), val.C); | |
func(gx::FieldTag<Nums, 3>(), val.D); | |
} | |
inline void forEachField(HasDefaults &val, auto &&func) { | |
} | |
inline void forEachField(HasString &val, auto &&func) { | |
} | |
inline void forEachField(Foo &val, auto &&func) { | |
} | |
template<> | |
struct gx::FieldTag<Bar, 0> { | |
inline static constexpr gx::FieldAttribs attribs { .name = "x" }; | |
}; | |
template<> | |
struct gx::FieldTag<Bar, 1> { | |
inline static constexpr gx::FieldAttribs attribs { .name = "y" }; | |
}; | |
inline void forEachField(Bar &val, auto &&func) { | |
func(gx::FieldTag<Bar, 0>(), val.X); | |
func(gx::FieldTag<Bar, 1>(), val.Y); | |
} | |
// | |
// Function declarations | |
// | |
int fib(int n); | |
void testFib(); | |
void testUnary(); | |
void testVariables(); | |
void testIncDec(); | |
void testIf(); | |
void testFor(); | |
void setToFortyTwo(int *ptr); | |
void testPointer(); | |
int outerSum(Outer o); | |
void setXToFortyTwo(Outer *o); | |
void testStruct(); | |
float sum(Point p); | |
void setZero(Point *p); | |
void testMethod(); | |
template<typename T> | |
T add(T a, T b); | |
template<typename T> | |
void incrHolder(Holder<T> *h); | |
template<typename T> | |
T get(Holder<T> h); | |
template<typename T> | |
void set(Holder<T> *h, T Item); | |
void testGenerics(); | |
void iterateOneToTen(auto &&f); | |
void testLambdas(); | |
void setSecondElementToThree(gx::Array<int, 4> *arr); | |
void testArrays(); | |
void appendFortyTwo(gx::Slice<int> *s); | |
void testSlices(); | |
template<typename T> | |
int len(Seq<T> *s); | |
template<typename T> | |
void add(Seq<T> *s, T val); | |
template<typename T, typename PT> | |
void incrSeq(Seq<T> *s); | |
void incr(SingleIncr *s); | |
void incr(DoubleIncr *s); | |
void testSeqs(); | |
void setGlobalXToFortyTwo(); | |
void checkGlobalXIsFortyTwo(); | |
int three(); | |
bool isGlobalSliceEmpty(); | |
int apply(int val, auto &&fn); | |
void testGlobalVariables(); | |
void testImports(); | |
void testExterns(); | |
void testConversions(); | |
void testMeta(); | |
void testDefaults(); | |
void testStrings(); | |
int main(); | |
void check(bool val); | |
int Val(Foo *f); | |
Foo NewFoo(int val); | |
// | |
// Variables | |
// | |
constexpr int initialGlobalX = 23; | |
int globalX = initialGlobalX; | |
int globalZ = 14; | |
int globalW = globalX + 42; | |
int globalY = globalX - three(); | |
gx::Slice<int> globalSlice; | |
int globalApplied = apply(3, [](int i) { | |
return 2 * i; | |
}); | |
constexpr Enum ZeroEnum = 0; | |
constexpr int OneEnum = 1; | |
constexpr int TwoEnum = 2; | |
// | |
// Function definitions | |
// | |
int fib(int n) { | |
if (n <= 1) { | |
return n; | |
} else { | |
return fib(n - 1) + fib(n - 2); | |
} | |
} | |
void testFib() { | |
check(fib(6) == 8); | |
} | |
void testUnary() { | |
check(-(3) == -3); | |
check(+(3) == 3); | |
} | |
void testVariables() { | |
auto x = 3; | |
auto y = 4; | |
check(x == 3); | |
check(y == 4); | |
y = y + 2; | |
x = x + 1; | |
check(y == 6); | |
check(x == 4); | |
y += 2; | |
x += 1; | |
check(y == 8); | |
check(x == 5); | |
} | |
void testIncDec() { | |
auto x = 0; | |
(x)++; | |
check(x == 1); | |
(x)--; | |
check(x == 0); | |
} | |
void testIf() { | |
auto x = 0; | |
if (auto cond = false; cond) { | |
x = 2; | |
} | |
check(x == 0); | |
} | |
void testFor() { | |
{ | |
auto sum = 0; | |
for (auto i = 0; i < 5; (i)++) { | |
sum += i; | |
} | |
check(sum == 10); | |
} | |
{ | |
auto sum = 0; | |
auto i = 0; | |
for (; i < 5; ) { | |
sum += i; | |
(i)++; | |
} | |
check(sum == 10); | |
} | |
{ | |
auto sum = 0; | |
auto i = 0; | |
for (; ; ) { | |
if (i >= 5) { | |
break; | |
} | |
sum += i; | |
(i)++; | |
} | |
check(sum == 10); | |
} | |
} | |
void setToFortyTwo(int *ptr) { | |
gx::deref(ptr) = 42; | |
} | |
void testPointer() { | |
auto val = 42; | |
check(val == 42); | |
auto ptr = &val; | |
gx::deref(ptr) = 14; | |
check(val == 14); | |
setToFortyTwo(ptr); | |
check(val == 42); | |
} | |
int outerSum(Outer o) { | |
return o.x + o.y + o.inner.z; | |
} | |
void setXToFortyTwo(Outer *o) { | |
gx::deref(o).x = 42; | |
} | |
void testStruct() { | |
{ | |
auto s = Outer {}; | |
check(s.x == 0); | |
check(s.y == 0); | |
check(s.inner.z == 0); | |
{ | |
auto p = &s; | |
gx::deref(p).x = 2; | |
check(gx::deref(p).x == 2); | |
check(s.x == 2); | |
s.y = 4; | |
check(gx::deref(p).y == 4); | |
} | |
check(outerSum(s) == 6); | |
setXToFortyTwo(&s); | |
check(s.x == 42); | |
} | |
{ | |
auto s = Outer { 2, 3, Inner { 4 } }; | |
check(s.x == 2); | |
check(s.y == 3); | |
check(s.inner.z == 4); | |
s.x += 1; | |
s.y += 1; | |
s.inner.z += 1; | |
check(s.x == 3); | |
check(s.y == 4); | |
check(s.inner.z == 5); | |
} | |
{ | |
auto s = Outer { .x = 2, .y = 3, .inner = Inner { .z = 4 } }; | |
check(s.x == 2); | |
check(s.y == 3); | |
check(s.inner.z == 4); | |
} | |
{ | |
auto s = Outer { | |
.x = 2, | |
.y = 3, | |
.inner = Inner { | |
.z = 4, | |
}, | |
}; | |
check(s.x == 2); | |
check(s.y == 3); | |
check(s.inner.z == 4); | |
} | |
{ | |
} | |
{ | |
auto i = 42; | |
auto p = &i; | |
auto pp = &p; | |
auto d = PtrPtr { pp }; | |
gx::deref(gx::deref(d.pp)) = 14; | |
check(d.pp != nullptr); | |
check(i == 14); | |
} | |
{ | |
auto p = PtrPtr {}; | |
check(p.pp == nullptr); | |
} | |
} | |
float sum(Point p) { | |
return p.x + p.y; | |
} | |
void setZero(Point *p) { | |
gx::deref(p).x = 0; | |
gx::deref(p).y = 0; | |
} | |
void testMethod() { | |
auto p = Point { 2, 3 }; | |
check(sum(p) == 5); | |
auto ptr = &p; | |
check(sum(gx::deref(ptr)) == 5); | |
setZero(&(p)); | |
check(p.x == 0); | |
check(p.y == 0); | |
} | |
template<typename T> | |
T add(T a, T b) { | |
return a + b; | |
} | |
template<typename T> | |
void incrHolder(Holder<T> *h) { | |
gx::deref(h).Item += 1; | |
} | |
template<typename T> | |
T get(Holder<T> h) { | |
return h.Item; | |
} | |
template<typename T> | |
void set(Holder<T> *h, T Item) { | |
gx::deref(h).Item = Item; | |
} | |
void testGenerics() { | |
{ | |
check(add<int>(1, 2) == 3); | |
check(add<float>(1.2f, 2.0f) == 3.2f); | |
check(add<float>(1.2f, 2.0f) == 3.2f); | |
} | |
{ | |
auto i = Holder<int> { 42 }; | |
check(i.Item == 42); | |
incrHolder<int>(&i); | |
check(i.Item == 43); | |
auto f = Holder<float> { 42 }; | |
check(f.Item == 42); | |
check(add<float>(f.Item, 20) == 62); | |
incrHolder<float>(&f); | |
check(f.Item == 43); | |
auto p = Holder<Point> { Point { 1, 2 } }; | |
check(p.Item.x == 1); | |
check(p.Item.y == 2); | |
setZero(&(p.Item)); | |
check(p.Item.x == 0); | |
check(p.Item.y == 0); | |
set(&(p), Point { 3, 2 }); | |
check(p.Item.x == 3); | |
check(p.Item.y == 2); | |
check(get(p).x == 3); | |
check(get(p).y == 2); | |
} | |
} | |
void iterateOneToTen(auto &&f) { | |
for (auto i = 1; i <= 10; (i)++) { | |
f(i); | |
} | |
} | |
void testLambdas() { | |
{ | |
auto val = 42; | |
check(val == 42); | |
auto foo = [&](int newVal) { | |
val = newVal; | |
}; | |
foo(14); | |
check(val == 14); | |
auto val2 = [&]() { | |
return val; | |
}(); | |
check(val2 == val); | |
} | |
{ | |
auto sum = 0; | |
iterateOneToTen([&](int i) { | |
sum += i; | |
}); | |
check(sum == 55); | |
} | |
} | |
void setSecondElementToThree(gx::Array<int, 4> *arr) { | |
gx::deref(arr)[1] = 3; | |
} | |
void testArrays() { | |
{ | |
auto arr = gx::Array<int, 4> { 1, 2, 3, 4 }; | |
check(arr[2] == 3); | |
auto sum = 0; | |
for (auto i = 0; i < gx::len(arr); (i)++) { | |
sum += arr[i]; | |
} | |
check(sum == 10); | |
check(arr[1] == 2); | |
setSecondElementToThree(&arr); | |
check(arr[1] == 3); | |
} | |
{ | |
auto stuff = gx::Array<int, 3> { 1, 2, 3 }; | |
check(gx::len(stuff) == 3); | |
auto sum = 0; | |
for (auto i = -1; auto &elem : stuff) { | |
++i; | |
check(i + 1 == elem); | |
sum += elem; | |
} | |
check(sum == 6); | |
} | |
{ | |
auto arr = gx::Array<gx::Array<int, 2>, 2> { gx::Array<int, 2> { 1, 2 }, gx::Array<int, 2> { 3, 4 } }; | |
check(gx::len(arr) == 2); | |
check(arr[0][0] == 1); | |
check(arr[0][1] == 2); | |
check(arr[1][0] == 3); | |
check(arr[1][1] == 4); | |
} | |
{ | |
auto h = HasArray {}; | |
check(gx::len(h.arr) == 4); | |
check(h.arr[0] == 0); | |
check(h.arr[1] == 0); | |
check(h.arr[2] == 0); | |
check(h.arr[3] == 0); | |
} | |
{ | |
auto h = HasArray { gx::Array<int, 4> { 1, 2, 3, 4 } }; | |
check(gx::len(h.arr) == 4); | |
check(h.arr[2] == 3); | |
} | |
} | |
void appendFortyTwo(gx::Slice<int> *s) { | |
gx::deref(s) = gx::append(gx::deref(s), 42); | |
} | |
void testSlices() { | |
{ | |
auto s = gx::Slice<int> {}; | |
check(gx::len(s) == 0); | |
s = gx::append(s, 1); | |
s = gx::append(s, 2); | |
check(gx::len(s) == 2); | |
check(s[0] == 1); | |
check(s[1] == 2); | |
appendFortyTwo(&s); | |
check(gx::len(s) == 3); | |
check(s[2] == 42); | |
} | |
{ | |
auto s = gx::Slice<gx::Slice<int>> { gx::Slice<int> { 1 }, gx::Slice<int> {}, gx::Slice<int> { 3, 4 } }; | |
check(gx::len(s) == 3); | |
check(gx::len(s[0]) == 1); | |
check(s[0][0] == 1); | |
check(gx::len(s[1]) == 0); | |
check(gx::len(s[2]) == 2); | |
check(s[2][0] == 3); | |
check(s[2][1] == 4); | |
} | |
{ | |
auto stuff = gx::Slice<int> { 1, 2 }; | |
stuff = gx::append(stuff, 3); | |
check(gx::len(stuff) == 3); | |
{ | |
auto sum = 0; | |
for (auto i = -1; auto &elem : stuff) { | |
++i; | |
check(i + 1 == elem); | |
sum += elem; | |
} | |
check(sum == 6); | |
} | |
{ | |
auto sum = 0; | |
for (auto i = -1; auto &_ [[maybe_unused]] : stuff) { | |
++i; | |
sum += i; | |
} | |
check(sum == 3); | |
} | |
{ | |
auto sum = 0; | |
for (auto &elem : stuff) { | |
sum += elem; | |
} | |
check(sum == 6); | |
} | |
{ | |
auto count = 0; | |
for (auto &_ [[maybe_unused]] : stuff) { | |
count += 1; | |
} | |
check(count == 3); | |
} | |
{ | |
stuff = gx::Slice<int> {}; | |
auto count = 0; | |
for (auto &_ [[maybe_unused]] : stuff) { | |
count += 1; | |
} | |
check(count == 0); | |
} | |
} | |
} | |
template<typename T> | |
int len(Seq<T> *s) { | |
return gx::len(gx::deref(s)); | |
} | |
template<typename T> | |
void add(Seq<T> *s, T val) { | |
gx::deref(s) = gx::append(gx::deref(s), val); | |
} | |
template<typename T, typename PT> | |
void incrSeq(Seq<T> *s) { | |
for (auto i = -1; auto &_ [[maybe_unused]] : gx::deref(s)) { | |
++i; | |
incr(PT(&(gx::deref(s))[i])); | |
} | |
} | |
void incr(SingleIncr *s) { | |
gx::deref(s).val += 1; | |
} | |
void incr(DoubleIncr *s) { | |
gx::deref(s).val += 2; | |
} | |
void testSeqs() { | |
{ | |
auto s = Seq<int> {}; | |
check(len(&(s)) == 0); | |
add(&(s), 1); | |
add(&(s), 2); | |
check(len(&(s)) == 2); | |
check(s[0] == 1); | |
check(s[1] == 2); | |
} | |
{ | |
auto s = Seq<int> { 1, 2, 3 }; | |
check(len(&(s)) == 3); | |
auto sum = 0; | |
for (auto i = -1; auto &elem : s) { | |
++i; | |
check(i + 1 == elem); | |
sum += elem; | |
} | |
check(sum == 6); | |
} | |
{ | |
auto s = Seq<Point> { Point { 1, 2 }, Point { 3, 4 } }; | |
check(len(&(s)) == 2); | |
check(s[0].x == 1); | |
check(s[0].y == 2); | |
check(s[1].x == 3); | |
check(s[1].y == 4); | |
add(&(s), Point { 5, 6 }); | |
check(s[2].x == 5); | |
check(s[2].y == 6); | |
} | |
{ | |
auto s = Seq<Point> { Point { .x = 1, .y = 2 }, Point { .x = 3, .y = 4 } }; | |
check(len(&(s)) == 2); | |
} | |
{ | |
auto s = Seq<Seq<int>> { Seq<int> { 1 }, Seq<int> {}, Seq<int> { 3, 4 } }; | |
check(len(&(s)) == 3); | |
check(gx::len(s[0]) == 1); | |
check(s[0][0] == 1); | |
check(len(&(s[1])) == 0); | |
check(len(&(s[2])) == 2); | |
check(s[2][0] == 3); | |
check(s[2][1] == 4); | |
} | |
{ | |
auto s = Seq<SingleIncr> { SingleIncr { 1 }, SingleIncr { 2 }, SingleIncr { 3 } }; | |
incrSeq<SingleIncr, SingleIncr *>(&s); | |
check(s[0].val == 2); | |
check(s[1].val == 3); | |
check(s[2].val == 4); | |
} | |
{ | |
auto s = Seq<DoubleIncr> { DoubleIncr { 1 }, DoubleIncr { 2 }, DoubleIncr { 3 } }; | |
incrSeq<DoubleIncr, DoubleIncr *>(&s); | |
check(s[0].val == 3); | |
check(s[1].val == 4); | |
check(s[2].val == 5); | |
} | |
} | |
void setGlobalXToFortyTwo() { | |
globalX = 42; | |
} | |
void checkGlobalXIsFortyTwo() { | |
check(globalX == 42); | |
} | |
int three() { | |
return 3; | |
} | |
bool isGlobalSliceEmpty() { | |
return gx::len(globalSlice) == 0; | |
} | |
int apply(int val, auto &&fn) { | |
return fn(val); | |
} | |
void testGlobalVariables() { | |
{ | |
check(globalX == 23); | |
check(globalY == 20); | |
check(globalZ == 14); | |
setGlobalXToFortyTwo(); | |
checkGlobalXIsFortyTwo(); | |
check(initialGlobalX == 23); | |
} | |
{ | |
check(isGlobalSliceEmpty()); | |
globalSlice = gx::append(globalSlice, 1); | |
globalSlice = gx::append(globalSlice, 2); | |
check(gx::len(globalSlice) == 2); | |
check(globalSlice[0] == 1); | |
check(globalSlice[1] == 2); | |
check(!isGlobalSliceEmpty()); | |
} | |
{ | |
check(globalApplied == 6); | |
} | |
{ | |
check(ZeroEnum == 0); | |
check(OneEnum == 1); | |
check(TwoEnum == 2); | |
} | |
} | |
void testImports() { | |
{ | |
auto f = Foo {}; | |
check(Val(&(f)) == 0); | |
} | |
{ | |
auto f = NewFoo(42); | |
check(Val(&(f)) == 42); | |
} | |
{ | |
auto b = Bar { .X = 2, .Y = 3 }; | |
check(b.X == 2); | |
check(b.Y == 3); | |
} | |
} | |
void testExterns() { | |
{ | |
check(rect::NUM_VERTICES == 4); | |
auto r = rect::Rect { .x = 100, .y = 100, .width = 20, .height = 30 }; | |
check(r.x == 100); | |
check(r.y == 100); | |
check(r.width == 20); | |
check(r.height == 30); | |
check(rect::area(r) == 600); | |
check(rect::area(r) == 600); | |
} | |
{ | |
check(person::Population == 0); | |
auto p = person::NewPerson(20, 100); | |
check(person::Population == 1); | |
check(person::GetAge(p) == 20); | |
check(person::GetHealth(p) == 100); | |
person::Grow(&(p)); | |
check(person::GetAge(p) == 21); | |
check(p.cppValue == 42); | |
check(person::GetAgeAdder(&(p))(1) == 22); | |
} | |
} | |
void testConversions() { | |
{ | |
auto f = float(2.2f); | |
auto i = int(f); | |
check(i == 2); | |
auto d = 2.2f; | |
check(f - float(d) == 0); | |
} | |
{ | |
auto slice = gx::Slice<int> { 1, 2 }; | |
auto seq = Seq<int>(slice); | |
add(&(seq), 3); | |
check(len(&(seq)) == 3); | |
check(seq[0] == 1); | |
check(seq[1] == 2); | |
check(seq[2] == 3); | |
} | |
} | |
void testMeta() { | |
auto n = Nums { 1, 2, 3, 4 }; | |
check(sumFields(n) == 14); | |
} | |
void testDefaults() { | |
auto h = HasDefaults {}; | |
check(h.foo == 42); | |
check(h.bar == 6.4f); | |
check(h.point.x == 1); | |
check(h.point.y == 2); | |
} | |
void testStrings() { | |
{ | |
gx::String s0 = ""; | |
check(gx::len(s0) == 0); | |
check(std::strcmp(s0, "") == 0); | |
gx::String s1 = "foo"; | |
check(gx::len(s1) == 3); | |
check(s1[0] == 'f'); | |
check(s1[1] == 'o'); | |
check(s1[2] == 'o'); | |
check(std::strcmp(s1, "foo") == 0); | |
gx::String s2 = "foo"; | |
check(std::strcmp(s1, s2) == 0); | |
check(std::strcmp(s1, "nope") != 0); | |
check(std::strcmp(s1, "foo") == 0); | |
check(s1 == s2); | |
check(s1 != "nope"); | |
check(s1 == gx::String("foo")); | |
check(s1 != gx::String("fao")); | |
gx::String s3 = s2; | |
check(std::strcmp(s1, s3) == 0); | |
auto sum = 0; | |
for (auto i = -1; auto &c : s3) { | |
++i; | |
sum += i; | |
if (i == 0) { | |
check(c == 'f'); | |
} | |
if (i == 1) { | |
check(c == 'o'); | |
} | |
if (i == 2) { | |
check(c == 'o'); | |
} | |
} | |
check(sum == 3); | |
} | |
{ | |
auto h0 = HasString {}; | |
check(gx::len(h0.s) == 0); | |
check(std::strcmp(h0.s, "") == 0); | |
auto h1 = HasString { "foo" }; | |
check(gx::len(h1.s) == 3); | |
check(h1.s[0] == 'f'); | |
check(h1.s[1] == 'o'); | |
check(h1.s[2] == 'o'); | |
check(std::strcmp(h1.s, "foo") == 0); | |
auto h2 = HasString { "foo" }; | |
check(std::strcmp(h1.s, h2.s) == 0); | |
check(std::strcmp(h1.s, HasString { "nope" }.s) != 0); | |
check(std::strcmp(h1.s, HasString { "foo" }.s) == 0); | |
auto h3 = h2; | |
check(std::strcmp(h1.s, h3.s) == 0); | |
} | |
} | |
int main() { | |
testFib(); | |
testUnary(); | |
testVariables(); | |
testIncDec(); | |
testIf(); | |
testFor(); | |
testPointer(); | |
testStruct(); | |
testMethod(); | |
testGenerics(); | |
testLambdas(); | |
testArrays(); | |
testSlices(); | |
testSeqs(); | |
testGlobalVariables(); | |
testImports(); | |
testExterns(); | |
testConversions(); | |
testMeta(); | |
testDefaults(); | |
testStrings(); | |
} | |
void check(bool val) { | |
if (val) { | |
gx::println("ok"); | |
} else { | |
gx::println("not ok"); | |
} | |
} | |
int Val(Foo *f) { | |
return gx::deref(f).val; | |
} | |
Foo NewFoo(int val) { | |
return Foo { val }; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//gx:include <string.h> | |
//gx:include "rect.hh" | |
//gx:include "sum_fields.hh" | |
package main | |
import ( | |
"github.com/nikki93/gx/example/foo" | |
"github.com/nikki93/gx/example/person" | |
) | |
// | |
// Basics | |
// | |
func fib(n int) int { | |
if n <= 1 { | |
return n | |
} else { | |
return fib(n-1) + fib(n-2) | |
} | |
} | |
func testFib() { | |
check(fib(6) == 8) | |
} | |
func testUnary() { | |
check(-(3) == -3) | |
check(+(3) == 3) | |
} | |
func testVariables() { | |
x := 3 | |
y := 4 | |
check(x == 3) | |
check(y == 4) | |
y = y + 2 | |
x = x + 1 | |
check(y == 6) | |
check(x == 4) | |
y += 2 | |
x += 1 | |
check(y == 8) | |
check(x == 5) | |
} | |
func testIncDec() { | |
x := 0 | |
x++ | |
check(x == 1) | |
x-- | |
check(x == 0) | |
} | |
func testIf() { | |
x := 0 | |
if cond := false; cond { | |
x = 2 | |
} | |
check(x == 0) | |
} | |
func testFor() { | |
{ | |
sum := 0 | |
for i := 0; i < 5; i++ { | |
sum += i | |
} | |
check(sum == 10) | |
} | |
{ | |
sum := 0 | |
i := 0 | |
for i < 5 { | |
sum += i | |
i++ | |
} | |
check(sum == 10) | |
} | |
{ | |
sum := 0 | |
i := 0 | |
for { | |
if i >= 5 { | |
break | |
} | |
sum += i | |
i++ | |
} | |
check(sum == 10) | |
} | |
} | |
// | |
// Pointers | |
// | |
func setToFortyTwo(ptr *int) { | |
*ptr = 42 | |
} | |
func testPointer() { | |
val := 42 | |
check(val == 42) | |
ptr := &val | |
*ptr = 14 | |
check(val == 14) | |
setToFortyTwo(ptr) | |
check(val == 42) | |
} | |
// | |
// Structs | |
// | |
type Outer struct { | |
x int | |
y int | |
inner Inner | |
} | |
type Inner struct { | |
z int | |
} | |
func outerSum(o Outer) int { | |
return o.x + o.y + o.inner.z | |
} | |
func setXToFortyTwo(o *Outer) { | |
o.x = 42 | |
} | |
type PtrPtr struct { | |
pp **int // Should be formatted as `int **pp;` in C++ | |
} | |
func testStruct() { | |
{ | |
s := Outer{} | |
check(s.x == 0) | |
check(s.y == 0) | |
check(s.inner.z == 0) | |
{ | |
p := &s | |
p.x = 2 | |
check(p.x == 2) | |
check(s.x == 2) | |
s.y = 4 | |
check(p.y == 4) | |
} | |
check(outerSum(s) == 6) | |
setXToFortyTwo(&s) | |
check(s.x == 42) | |
} | |
{ | |
s := Outer{2, 3, Inner{4}} | |
check(s.x == 2) | |
check(s.y == 3) | |
check(s.inner.z == 4) | |
s.x += 1 | |
s.y += 1 | |
s.inner.z += 1 | |
check(s.x == 3) | |
check(s.y == 4) | |
check(s.inner.z == 5) | |
} | |
{ | |
s := Outer{x: 2, y: 3, inner: Inner{z: 4}} | |
check(s.x == 2) | |
check(s.y == 3) | |
check(s.inner.z == 4) | |
} | |
{ | |
s := Outer{ | |
x: 2, | |
y: 3, | |
inner: Inner{ | |
z: 4, | |
}, | |
} | |
check(s.x == 2) | |
check(s.y == 3) | |
check(s.inner.z == 4) | |
} | |
{ | |
// Out-of-order elements in struct literal no longer allowed | |
//s := Outer{ | |
// inner: Inner{ | |
// z: 4, | |
// }, | |
// y: 3, | |
// x: 2, | |
//} | |
} | |
{ | |
i := 42 | |
p := &i | |
pp := &p | |
d := PtrPtr{pp} | |
**d.pp = 14 | |
check(d.pp != nil) | |
check(i == 14) | |
} | |
{ | |
p := PtrPtr{} | |
check(p.pp == nil) | |
} | |
} | |
// | |
// Methods | |
// | |
type Point struct { | |
x, y float32 | |
} | |
func (p Point) sum() float32 { | |
return p.x + p.y | |
} | |
func (p *Point) setZero() { | |
p.x = 0 | |
p.y = 0 | |
} | |
func testMethod() { | |
p := Point{2, 3} | |
check(p.sum() == 5) | |
ptr := &p | |
check(ptr.sum() == 5) // Pointer as value receiver | |
p.setZero() // Addressable value as pointer receiver | |
check(p.x == 0) | |
check(p.y == 0) | |
} | |
// | |
// Generics | |
// | |
type Numeric interface { | |
int | float64 | |
} | |
func add[T Numeric](a, b T) T { | |
return a + b | |
} | |
type Holder[T any] struct { | |
Item T | |
} | |
func incrHolder[T Numeric](h *Holder[T]) { | |
h.Item += 1 | |
} | |
func (h Holder[T]) get() T { | |
return h.Item | |
} | |
func (h *Holder[T]) set(Item T) { | |
h.Item = Item | |
} | |
func testGenerics() { | |
{ | |
check(add(1, 2) == 3) | |
check(add(1.2, 2.0) == 3.2) | |
check(add[float64](1.2, 2.0) == 3.2) | |
} | |
{ | |
i := Holder[int]{42} | |
check(i.Item == 42) | |
incrHolder(&i) | |
check(i.Item == 43) | |
f := Holder[float64]{42} | |
check(f.Item == 42) | |
check(add(f.Item, 20) == 62) | |
incrHolder(&f) | |
check(f.Item == 43) | |
p := Holder[Point]{Point{1, 2}} | |
check(p.Item.x == 1) | |
check(p.Item.y == 2) | |
p.Item.setZero() | |
check(p.Item.x == 0) | |
check(p.Item.y == 0) | |
p.set(Point{3, 2}) | |
check(p.Item.x == 3) | |
check(p.Item.y == 2) | |
check(p.get().x == 3) | |
check(p.get().y == 2) | |
} | |
} | |
// | |
// Lambdas | |
// | |
func iterateOneToTen(f func(int)) { | |
for i := 1; i <= 10; i++ { | |
f(i) | |
} | |
} | |
func testLambdas() { | |
{ | |
val := 42 | |
check(val == 42) | |
foo := func(newVal int) { | |
val = newVal | |
} | |
foo(14) | |
check(val == 14) | |
val2 := func() int { | |
return val | |
}() | |
check(val2 == val) | |
} | |
{ | |
sum := 0 | |
iterateOneToTen(func(i int) { | |
sum += i | |
}) | |
check(sum == 55) | |
} | |
} | |
// | |
// Arrays | |
// | |
func setSecondElementToThree(arr *[4]int) { | |
arr[1] = 3 | |
} | |
type HasArray struct { | |
arr [4]int | |
} | |
func testArrays() { | |
{ | |
arr := [4]int{1, 2, 3, 4} | |
check(arr[2] == 3) | |
sum := 0 | |
for i := 0; i < len(arr); i++ { | |
sum += arr[i] | |
} | |
check(sum == 10) | |
check(arr[1] == 2) | |
setSecondElementToThree(&arr) | |
check(arr[1] == 3) | |
} | |
{ | |
stuff := [...]int{1, 2, 3} | |
check(len(stuff) == 3) | |
sum := 0 | |
for i, elem := range stuff { | |
check(i+1 == elem) | |
sum += elem | |
} | |
check(sum == 6) | |
// Other cases of for-range are checked in `testSlices` | |
} | |
{ | |
arr := [...][2]int{{1, 2}, {3, 4}} | |
check(len(arr) == 2) | |
check(arr[0][0] == 1) | |
check(arr[0][1] == 2) | |
check(arr[1][0] == 3) | |
check(arr[1][1] == 4) | |
} | |
{ | |
h := HasArray{} | |
check(len(h.arr) == 4) | |
check(h.arr[0] == 0) | |
check(h.arr[1] == 0) | |
check(h.arr[2] == 0) | |
check(h.arr[3] == 0) | |
} | |
{ | |
h := HasArray{[4]int{1, 2, 3, 4}} | |
check(len(h.arr) == 4) | |
check(h.arr[2] == 3) | |
} | |
} | |
// | |
// Slices | |
// | |
func appendFortyTwo(s *[]int) { | |
*s = append(*s, 42) | |
} | |
func testSlices() { | |
{ | |
s := []int{} | |
check(len(s) == 0) | |
s = append(s, 1) | |
s = append(s, 2) | |
check(len(s) == 2) | |
check(s[0] == 1) | |
check(s[1] == 2) | |
appendFortyTwo(&s) | |
check(len(s) == 3) | |
check(s[2] == 42) | |
} | |
{ | |
s := [][]int{{1}, {}, {3, 4}} | |
check(len(s) == 3) | |
check(len(s[0]) == 1) | |
check(s[0][0] == 1) | |
check(len(s[1]) == 0) | |
check(len(s[2]) == 2) | |
check(s[2][0] == 3) | |
check(s[2][1] == 4) | |
} | |
{ | |
stuff := []int{1, 2} | |
stuff = append(stuff, 3) | |
check(len(stuff) == 3) | |
{ | |
sum := 0 | |
for i, elem := range stuff { | |
check(i+1 == elem) | |
sum += elem | |
} | |
check(sum == 6) | |
} | |
{ | |
sum := 0 | |
for i := range stuff { | |
sum += i | |
} | |
check(sum == 3) | |
} | |
{ | |
sum := 0 | |
for _, elem := range stuff { | |
sum += elem | |
} | |
check(sum == 6) | |
} | |
{ | |
count := 0 | |
for range stuff { | |
count += 1 | |
} | |
check(count == 3) | |
} | |
{ | |
stuff = []int{} | |
count := 0 | |
for range stuff { | |
count += 1 | |
} | |
check(count == 0) | |
} | |
} | |
} | |
// | |
// Seq (generic slice with own methods) | |
// | |
type Seq[T any] []T | |
func (s *Seq[T]) len() int { | |
return len(*s) | |
} | |
func (s *Seq[T]) add(val T) { | |
*s = append(*s, val) | |
} | |
type Increr[T any] interface { | |
*T | |
incr() | |
} | |
func incrSeq[T any, PT Increr[T]](s *Seq[T]) { | |
for i := range *s { | |
PT(&(*s)[i]).incr() | |
} | |
} | |
type SingleIncr struct { | |
val int | |
} | |
func (s *SingleIncr) incr() { | |
s.val += 1 | |
} | |
type DoubleIncr struct { | |
val int | |
} | |
func (s *DoubleIncr) incr() { | |
s.val += 2 | |
} | |
func testSeqs() { | |
{ | |
s := Seq[int]{} | |
check(s.len() == 0) | |
s.add(1) | |
s.add(2) | |
check(s.len() == 2) | |
check(s[0] == 1) | |
check(s[1] == 2) | |
} | |
{ | |
s := Seq[int]{1, 2, 3} | |
check(s.len() == 3) | |
sum := 0 | |
for i, elem := range s { | |
check(i+1 == elem) | |
sum += elem | |
} | |
check(sum == 6) | |
} | |
{ | |
s := Seq[Point]{{1, 2}, {3, 4}} | |
check(s.len() == 2) | |
check(s[0].x == 1) | |
check(s[0].y == 2) | |
check(s[1].x == 3) | |
check(s[1].y == 4) | |
s.add(Point{5, 6}) | |
check(s[2].x == 5) | |
check(s[2].y == 6) | |
} | |
{ | |
s := Seq[Point]{{x: 1, y: 2}, {x: 3, y: 4}} | |
check(s.len() == 2) | |
} | |
{ | |
s := Seq[Seq[int]]{{1}, {}, {3, 4}} | |
check(s.len() == 3) | |
check(len(s[0]) == 1) | |
check(s[0][0] == 1) | |
check(s[1].len() == 0) | |
check(s[2].len() == 2) | |
check(s[2][0] == 3) | |
check(s[2][1] == 4) | |
} | |
{ | |
s := Seq[SingleIncr]{{1}, {2}, {3}} | |
incrSeq(&s) | |
check(s[0].val == 2) | |
check(s[1].val == 3) | |
check(s[2].val == 4) | |
} | |
{ | |
s := Seq[DoubleIncr]{{1}, {2}, {3}} | |
incrSeq(&s) | |
check(s[0].val == 3) | |
check(s[1].val == 4) | |
check(s[2].val == 5) | |
} | |
} | |
// | |
// Global variables | |
// | |
var globalY = globalX - three() | |
var globalX, globalZ = initialGlobalX, 14 | |
var globalSlice []int | |
const initialGlobalX = 23 | |
func setGlobalXToFortyTwo() { | |
globalX = 42 | |
} | |
func checkGlobalXIsFortyTwo() { | |
check(globalX == 42) | |
} | |
func three() int { | |
return 3 | |
} | |
func isGlobalSliceEmpty() bool { | |
return len(globalSlice) == 0 | |
} | |
func apply(val int, fn func(int) int) int { | |
return fn(val) | |
} | |
var globalApplied = apply(3, func(i int) int { return 2 * i }) | |
type Enum int | |
const ( | |
ZeroEnum Enum = 0 | |
OneEnum = 1 | |
TwoEnum = 2 | |
) | |
func testGlobalVariables() { | |
{ | |
check(globalX == 23) | |
check(globalY == 20) | |
check(globalZ == 14) | |
setGlobalXToFortyTwo() | |
checkGlobalXIsFortyTwo() | |
check(initialGlobalX == 23) | |
} | |
{ | |
check(isGlobalSliceEmpty()) | |
globalSlice = append(globalSlice, 1) | |
globalSlice = append(globalSlice, 2) | |
check(len(globalSlice) == 2) | |
check(globalSlice[0] == 1) | |
check(globalSlice[1] == 2) | |
check(!isGlobalSliceEmpty()) | |
} | |
{ | |
check(globalApplied == 6) | |
} | |
{ | |
check(ZeroEnum == 0) | |
check(OneEnum == 1) | |
check(TwoEnum == 2) | |
} | |
} | |
// | |
// Imports | |
// | |
func testImports() { | |
{ | |
f := foo.Foo{} | |
check(f.Val() == 0) | |
} | |
{ | |
f := foo.NewFoo(42) | |
check(f.Val() == 42) | |
} | |
{ | |
b := foo.Bar{X: 2, Y: 3} | |
check(b.X == 2) | |
check(b.Y == 3) | |
} | |
} | |
// | |
// Externs | |
// | |
//gx:extern rect::NUM_VERTICES | |
const RectNumVertices = 0 // Ensure use of actual C++ constant value | |
//gx:extern rect::Rect | |
type Rect struct { | |
X, Y float32 | |
Width, Height float32 | |
} | |
//gx:extern rect::area | |
func area(r Rect) float32 | |
//gx:extern rect::area | |
func (r Rect) area() float32 | |
func testExterns() { | |
{ | |
check(RectNumVertices == 4) | |
r := Rect{X: 100, Y: 100, Width: 20, Height: 30} | |
check(r.X == 100) | |
check(r.Y == 100) | |
check(r.Width == 20) | |
check(r.Height == 30) | |
check(area(r) == 600) | |
check(r.area() == 600) | |
} | |
{ | |
check(person.Population == 0) | |
p := person.NewPerson(20, 100) | |
check(person.Population == 1) | |
check(p.Age() == 20) | |
check(p.Health() == 100) | |
p.Grow() | |
check(p.Age() == 21) | |
check(p.GXValue == 42) | |
check(p.GetAgeAdder()(1) == 22) | |
} | |
} | |
// | |
// Conversions | |
// | |
func testConversions() { | |
{ | |
f := float32(2.2) | |
i := int(f) | |
check(i == 2) | |
d := 2.2 | |
check(f-float32(d) == 0) | |
} | |
{ | |
slice := []int{1, 2} | |
seq := Seq[int](slice) | |
seq.add(3) | |
check(seq.len() == 3) | |
check(seq[0] == 1) | |
check(seq[1] == 2) | |
check(seq[2] == 3) | |
} | |
} | |
// | |
// Meta | |
// | |
type Nums struct { | |
A, B, C int | |
D int `attribs:"twice"` | |
} | |
//gx:extern sumFields | |
func sumFields(val interface{}) int | |
func testMeta() { | |
n := Nums{1, 2, 3, 4} | |
check(sumFields(n) == 14) | |
} | |
// | |
// Defaults | |
// | |
type HasDefaults struct { | |
foo int `default:"42"` | |
bar float32 `default:"6.4"` | |
point Point `default:"{ 1, 2 }"` | |
} | |
func testDefaults() { | |
h := HasDefaults{} | |
check(h.foo == 42) | |
check(h.bar == 6.4) | |
check(h.point.x == 1) | |
check(h.point.y == 2) | |
} | |
// | |
// Strings | |
// | |
//gx:extern std::strcmp | |
func strcmp(a, b string) int | |
type HasString struct { | |
s string | |
} | |
func testStrings() { | |
{ | |
s0 := "" | |
check(len(s0) == 0) | |
check(strcmp(s0, "") == 0) | |
s1 := "foo" | |
check(len(s1) == 3) | |
check(s1[0] == 'f') | |
check(s1[1] == 'o') | |
check(s1[2] == 'o') | |
check(strcmp(s1, "foo") == 0) | |
s2 := "foo" | |
check(strcmp(s1, s2) == 0) | |
check(strcmp(s1, "nope") != 0) | |
check(strcmp(s1, "foo") == 0) | |
check(s1 == s2) | |
check(s1 != "nope") | |
check(s1 == string("foo")) | |
check(s1 != string("fao")) | |
s3 := s2 | |
check(strcmp(s1, s3) == 0) | |
sum := 0 | |
for i, c := range s3 { | |
sum += i | |
if i == 0 { | |
check(c == 'f') | |
} | |
if i == 1 { | |
check(c == 'o') | |
} | |
if i == 2 { | |
check(c == 'o') | |
} | |
} | |
check(sum == 3) | |
} | |
{ | |
h0 := HasString{} | |
check(len(h0.s) == 0) | |
check(strcmp(h0.s, "") == 0) | |
h1 := HasString{"foo"} | |
check(len(h1.s) == 3) | |
check(h1.s[0] == 'f') | |
check(h1.s[1] == 'o') | |
check(h1.s[2] == 'o') | |
check(strcmp(h1.s, "foo") == 0) | |
h2 := HasString{"foo"} | |
check(strcmp(h1.s, h2.s) == 0) | |
check(strcmp(h1.s, HasString{"nope"}.s) != 0) | |
check(strcmp(h1.s, HasString{"foo"}.s) == 0) | |
h3 := h2 | |
check(strcmp(h1.s, h3.s) == 0) | |
} | |
} | |
// | |
// Main | |
// | |
func main() { | |
testFib() | |
testUnary() | |
testVariables() | |
testIncDec() | |
testIf() | |
testFor() | |
testPointer() | |
testStruct() | |
testMethod() | |
testGenerics() | |
testLambdas() | |
testArrays() | |
testSlices() | |
testSeqs() | |
testGlobalVariables() | |
testImports() | |
testExterns() | |
testConversions() | |
testMeta() | |
testDefaults() | |
testStrings() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment