Hana 9e216da9ef go.mod: add go.mod and move pygments to third_party
After go1.16, go will use module mode by default,
even when the repository is checked out under GOPATH
or in a one-off directory. Add go.mod, go.sum to keep
this repo buildable without opting out of the module
mode.

> go mod init github.com/mmcgrana/gobyexample
> go mod tidy
> go mod vendor

In module mode, the 'vendor' directory is special
and its contents will be actively maintained by the
go command. pygments aren't the dependency the go will
know about, so it will delete the contents from vendor
directory. Move it to `third_party` directory now.

And, vendor the blackfriday package.

Note: the tutorial contents are not affected by the
change in go1.16 because all the examples in this
tutorial ask users to run the go command with the
explicit list of files to be compiled (e.g.
`go run hello-world.go` or `go build command-line-arguments.go`).
When the source list is provided, the go command does
not have to compute the build list and whether it's
running in GOPATH mode or module mode becomes irrelevant.
2021-02-15 16:45:26 -05:00

747 lines
11 KiB
Plaintext

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;
}
}
}