summaryrefslogtreecommitdiff
path: root/tests/examplefiles/simple.croc
diff options
context:
space:
mode:
Diffstat (limited to 'tests/examplefiles/simple.croc')
-rw-r--r--tests/examplefiles/simple.croc747
1 files changed, 747 insertions, 0 deletions
diff --git a/tests/examplefiles/simple.croc b/tests/examplefiles/simple.croc
new file mode 100644
index 00000000..8f12771a
--- /dev/null
+++ b/tests/examplefiles/simple.croc
@@ -0,0 +1,747 @@
+module simple;
+
+// Importing stuff.
+{
+ function loadMod(name, ns)
+ {
+ assert(name == "mod");
+
+ ns.x = "I'm x";
+
+ ns.foo = function foo()
+ {
+ writefln("foo");
+ };
+
+ ns.bar = function bar(x)
+ {
+ return x[0];
+ };
+
+ ns.baz = function baz()
+ {
+ writefln(x);
+ };
+
+ foreach(k, v; ns)
+ if(isFunction(v))
+ v.environment(ns);
+ }
+
+ setModuleLoader("mod", loadMod);
+
+ import mod : foo, bar;
+ foo();
+ writefln(bar([5]));
+ mod.baz();
+
+ writefln();
+}
+
+// Super calls.
+{
+ class Base
+ {
+ function fork()
+ {
+ writefln("Base fork.");
+ }
+ }
+
+ class Derived : Base
+ {
+ function fork()
+ {
+ writefln("Derived fork!");
+ super.fork();
+ }
+ }
+
+ local d = Derived();
+ d.fork();
+
+ writefln();
+}
+
+// Coroutines and coroutine iteration.
+{
+ local countDown = coroutine function countDown(x)
+ {
+ yield();
+
+ while(x > 0)
+ {
+ yield(x);
+ x--;
+ }
+ };
+
+ foreach(v; countDown, 5)
+ writefln(v);
+
+ writefln();
+
+ local forEach = coroutine function forEach(t)
+ {
+ yield();
+
+ foreach(k, v; t)
+ yield(k, v);
+ };
+
+ foreach(_, k, v; forEach, {hi = 1, bye = 2})
+ writefln("key: ", k, ", value: ", v);
+
+ writefln();
+}
+
+// Testing tailcalls.
+{
+ function recurse(x)
+ {
+ writefln("recurse: ", x);
+
+ if(x == 0)
+ return toString(x);
+ else
+ return recurse(x - 1);
+ }
+
+ writefln(recurse(5));
+ writefln();
+
+ class A
+ {
+ function f(x)
+ {
+ writefln("A.f: ", x);
+
+ if(x == 0)
+ return toString(x);
+ else
+ return this.f(x - 1); // call it as this.f to force a 'method' instruction to be generated
+ }
+ }
+
+ local a = A();
+ writefln(a.f(5));
+ writefln();
+}
+
+{
+ // A function which lets us define properties for a class.
+ // The varargs should be a bunch of tables, each with a 'name' field, and 'getter' and/or 'setter' fields.
+ function mixinProperties(classType, vararg)
+ {
+ classType.mProps = { };
+
+ classType.opIndex = function opIndex(key)
+ {
+ local prop = mProps[key];
+
+ if(prop is null)
+ throw format(classType, ".opIndex() - Property '%s' does not exist", key);
+
+ local getter = prop.getter;
+
+ if(getter is null)
+ throw format(classType, ".opIndex() - Property '%s' has no getter", key);
+
+ return getter(with this);
+ };
+
+ classType.opIndexAssign = function opIndexAssign(key, value)
+ {
+ local prop = mProps[key];
+
+ if(prop is null)
+ throw format(classType, ".opIndexAssign() - Property '%s' does not exist", key);
+
+ local setter = prop.setter;
+
+ if(setter is null)
+ throw format(classType, ".opIndexAssign() - Property '%s' has no setter", key);
+
+ setter(with this, value);
+ };
+
+ foreach(i, prop; [vararg])
+ {
+ if(!isTable(prop))
+ throw format("mixinProperties() - property ", i, " is not a table");
+
+ if(prop.name is null)
+ throw format("mixinProperties() - property ", i, " has no name");
+
+ if(prop.setter is null && prop.getter is null)
+ throw format("mixinProperties() - property '%s' has no getter or setter", prop.name);
+
+ classType.mProps[prop.name] = prop;
+ }
+ }
+
+ // Create a class to test out.
+ class PropTest
+ {
+ mX = 0;
+ mY = 0;
+ mName = "";
+
+ function constructor(name)
+ {
+ mName = name;
+ }
+
+ function toString()
+ {
+ return format("name = '", mName, "' x = ", mX, " y = ", mY);
+ }
+ }
+
+ // Mix in the properties.
+ mixinProperties
+ (
+ PropTest,
+
+ {
+ name = "x",
+
+ function setter(value)
+ {
+ mX = value;
+ }
+
+ function getter()
+ {
+ return mX;
+ }
+ },
+
+ {
+ name = "y",
+
+ function setter(value)
+ {
+ mY = value;
+ }
+
+ function getter()
+ {
+ return mY;
+ }
+ },
+
+ {
+ name = "name",
+
+ function getter()
+ {
+ return mName;
+ }
+ }
+ );
+
+ // Create an instance and try it out.
+ local p = PropTest("hello");
+
+ writefln(p);
+ p.x = 46;
+ p.y = 123;
+ p.x = p.x + p.y;
+ writefln(p);
+
+ // Try to access a nonexistent property.
+ try
+ p.name = "crap";
+ catch(e)
+ {
+ writefln("caught: ", e);
+ writefln(getTraceback());
+ }
+
+ writefln();
+}
+
+// Some container classes.
+{
+ class PQ
+ {
+ mData;
+ mLength = 0;
+
+ function constructor()
+ {
+ mData = array.new(15);
+ }
+
+ function insert(data)
+ {
+ resizeArray();
+ mData[mLength] = data;
+
+ local index = mLength;
+ local parentIndex = (index - 1) / 2;
+
+ while(index > 0 && mData[parentIndex] > mData[index])
+ {
+ local temp = mData[parentIndex];
+ mData[parentIndex] = mData[index];
+ mData[index] = temp;
+
+ index = parentIndex;
+ parentIndex = (index - 1) / 2;
+ }
+
+ mLength += 1;
+ }
+
+ function remove()
+ {
+ if(mLength == 0)
+ throw "PQ.remove() - No items to remove";
+
+ local data = mData[0];
+ mLength -= 1;
+ mData[0] = mData[mLength];
+
+ local index = 0;
+ local left = 1;
+ local right = 2;
+
+ while(index < mLength)
+ {
+ local smaller;
+
+ if(left >= mLength)
+ {
+ if(right >= mLength)
+ break;
+ else
+ smaller = right;
+ }
+ else
+ {
+ if(right >= mLength)
+ smaller = left;
+ else
+ {
+ if(mData[left] < mData[right])
+ smaller = left;
+ else
+ smaller = right;
+ }
+ }
+
+ if(mData[index] > mData[smaller])
+ {
+ local temp = mData[index];
+ mData[index] = mData[smaller];
+ mData[smaller] = temp;
+
+ index = smaller;
+ left = (index * 2) + 1;
+ right = left + 1;
+ }
+ else
+ break;
+ }
+
+ return data;
+ }
+
+ function resizeArray()
+ {
+ if(mLength >= #mData)
+ mData.length((#mData + 1) * 2 - 1);
+ }
+
+ function hasData()
+ {
+ return mLength != 0;
+ }
+ }
+
+ class Stack
+ {
+ mHead = null;
+
+ function push(data)
+ {
+ local t = { data = data, next = mHead };
+ mHead = t;
+ }
+
+ function pop()
+ {
+ if(mHead is null)
+ throw "Stack.pop() - No items to pop";
+
+ local item = mHead;
+ mHead = mHead.next;
+
+ return item.data;
+ }
+
+ function hasData()
+ {
+ return mHead !is null;
+ }
+ }
+
+ class Queue
+ {
+ mHead = null;
+ mTail = null;
+
+ function push(data)
+ {
+ local t = { data = data, next = null };
+
+ if(mTail is null)
+ {
+ mHead = t;
+ mTail = t;
+ }
+ else
+ {
+ mTail.next = t;
+ mTail = t;
+ }
+ }
+
+ function pop()
+ {
+ if(mTail is null)
+ throw "Queue.pop() - No items to pop";
+
+ local item = mHead;
+ mHead = mHead.next;
+
+ if(mHead is null)
+ mTail = null;
+
+ return item.data;
+ }
+
+ function hasData()
+ {
+ return mHead !is null;
+ }
+ }
+
+ writefln("Priority queue (heap)");
+
+ local prioQ = PQ();
+
+ for(i : 0 .. 10)
+ prioQ.insert(math.rand(0, 20));
+
+ while(prioQ.hasData())
+ writefln(prioQ.remove());
+
+ writefln();
+ writefln("Stack");
+
+ local stack = Stack();
+
+ for(i : 0 .. 5)
+ stack.push(i + 1);
+
+ while(stack.hasData())
+ writefln(stack.pop());
+
+ writefln();
+ writefln("Queue");
+
+ local queue = Queue();
+
+ for(i : 0 .. 5)
+ queue.push(i + 1);
+
+ while(queue.hasData())
+ writefln(queue.pop());
+
+ writefln();
+}
+
+// opApply tests.
+{
+ class Test
+ {
+ mData = [4, 5, 6];
+
+ function opApply(extra)
+ {
+ if(isString(extra) && extra == "reverse")
+ {
+ local function iterator_reverse(index)
+ {
+ index--;
+
+ if(index < 0)
+ return;
+
+ return index, mData[index];
+ }
+
+ return iterator_reverse, this, #mData;
+ }
+ else
+ {
+ local function iterator(index)
+ {
+ index++;
+
+ if(index >= #mData)
+ return;
+
+ return index, mData[index];
+ }
+
+ return iterator, this, -1;
+ }
+ }
+ }
+
+ local test = Test();
+
+ foreach(k, v; test)
+ writefln("test[", k, "] = ", v);
+
+ writefln();
+
+ foreach(k, v; test, "reverse")
+ writefln("test[", k, "] = ", v);
+
+ writefln();
+
+ test =
+ {
+ fork = 5,
+ knife = 10,
+ spoon = "hi"
+ };
+
+ foreach(k, v; test)
+ writefln("test[", k, "] = ", v);
+
+ test = [5, 10, "hi"];
+
+ writefln();
+
+ foreach(k, v; test)
+ writefln("test[", k, "] = ", v);
+
+ writefln();
+
+ foreach(k, v; test, "reverse")
+ writefln("test[", k, "] = ", v);
+
+ writefln();
+
+ foreach(k, v; "hello")
+ writefln("str[", k, "] = ", v);
+
+ writefln();
+
+ foreach(k, v; "hello", "reverse")
+ writefln("str[", k, "] = ", v);
+
+ writefln();
+}
+
+// Testing upvalues in for loops.
+{
+ local arr = array.new(10);
+
+ for(i : 0 .. 10)
+ arr[i] = function() { return i; };
+
+ writefln("This should be the values 0 through 9:");
+
+ foreach(func; arr)
+ writefln(func());
+
+ writefln();
+}
+
+// Testing nested functions.
+{
+ function outer()
+ {
+ local x = 3;
+
+ function inner()
+ {
+ x++;
+ writefln("inner x: ", x);
+ }
+
+ writefln("outer x: ", x);
+ inner();
+ writefln("outer x: ", x);
+
+ return inner;
+ }
+
+ local func = outer();
+ func();
+
+ writefln();
+}
+
+// Testing Exceptions.
+{
+ function thrower(x)
+ {
+ if(x >= 3)
+ throw "Sorry, x is too big for me!";
+ }
+
+ function tryCatch(iterations)
+ {
+ try
+ {
+ for(i : 0 .. iterations)
+ {
+ writefln("tryCatch: ", i);
+ thrower(i);
+ }
+ }
+ catch(e)
+ {
+ writefln("tryCatch caught: ", e);
+ throw e;
+ }
+ finally
+ writefln("tryCatch finally");
+ }
+
+ try
+ {
+ tryCatch(2);
+ tryCatch(5);
+ }
+ catch(e)
+ writefln("caught: ", e);
+
+ writefln();
+}
+
+// Testing arrays.
+{
+ local array = [7, 9, 2, 3, 6];
+
+ array.sort();
+
+ foreach(i, v; array)
+ writefln("arr[", i, "] = ", v);
+
+ array ~= ["foo", "far"];
+
+ writefln();
+
+ foreach(i, v; array)
+ writefln("arr[", i, "] = ", v);
+
+ writefln();
+}
+
+// Testing vararg functions.
+{
+ function vargs(vararg)
+ {
+ local args = [vararg];
+
+ writefln("num varargs: ", #args);
+
+ foreach(i, v; args)
+ writefln("args[", i, "] = ", v);
+ }
+
+ vargs();
+
+ writefln();
+
+ vargs(2, 3, 5, "foo", "bar");
+
+ writefln();
+}
+
+// Testing switches.
+{
+ foreach(v; ["hi", "bye", "foo"])
+ {
+ switch(v)
+ {
+ case "hi":
+ writefln("switched to hi");
+ break;
+
+ case "bye":
+ writefln("switched to bye");
+ break;
+
+ default:
+ writefln("switched to something else");
+ break;
+ }
+ }
+
+ writefln();
+
+ foreach(v; [null, false, 1, 2.3, 'x', "hi"])
+ {
+ switch(v)
+ {
+ case null: writefln("null"); break;
+ case false: writefln("false"); break;
+ case 1: writefln("1"); break;
+ case 2.3: writefln("2.3"); break;
+ case 'x': writefln("x"); break;
+ case "hi": writefln("hi"); break;
+ }
+ }
+
+ writefln();
+
+ class A
+ {
+ mValue;
+
+ this(value)
+ {
+ mValue = value;
+ }
+
+ function opCmp(other)
+ {
+ assert(other as A);
+ return mValue <=> other.mValue;
+ }
+ }
+
+ local a1 = A(1);
+ local a2 = A(2);
+ local a3 = A(3);
+
+ for(s : 1 .. 4)
+ {
+ local ss = A(s);
+
+ switch(ss)
+ {
+ case a1:
+ writefln(1);
+ break;
+
+ case a2:
+ writefln(2);
+ break;
+
+ case a3:
+ writefln(3);
+ break;
+ }
+ }
+} \ No newline at end of file