BinaryTree
This example has a more complex macro definition called makeBinTree
, used to construct a binary tree through more convenient syntax.
Under the hood, a tree is a std.One
value pointing to a BinNode
. Using std.One
makes it easy to allocate nodes, and automatically cleans up the tree after use. This cleans up the entire tree, including all direct and indirect children nodes.
The macro uses various definitions from base.orb and std/One.orb. make
is used to initialize BinNode
and std.makeOneWith
is used to allocate a copy of that value on the heap and return a std.One
pointing to it. base.isOfType
and base.isEmptyRaw
help analyze user input.
The main
function uses this macro to build several trees more easily and perform some analysis on them.
binTree.orb
import "std/One.orb";
data BinNode {
val:i32
left:(std.One BinNode false)
right:(std.One BinNode false)
};
# couldn't define the drop function earlier due to circular definitions
std.defineDrop (std.One BinNode);
mac makeBinTree (tree) {
if (base.isOfType tree raw) {
# expecting three entries for each field of BinNode
if (!= (lenOf tree) 3) {
message::error tree::loc "Bad binary tree structure.";
};
# create a code snippet for initializing BinNode
sym (code \(make BinNode (val ,([] tree 0))));
# recursively construct left and right subtree
if (! (base.isEmptyRaw ([] tree 1))) {
= code (+ code \((left (makeBinTree ,([] tree 1)))));
};
if (! (base.isEmptyRaw ([] tree 2))) {
= code (+ code \((right (makeBinTree ,([] tree 2)))));
};
# return code that initializes std.One pointing to a BinNode
ret \(std.makeOneWith ,code);
};
# else, it's a leaf node
ret \(std.makeOneWith (make BinNode (val ,tree)));
};
main.orb
import "base.orb";
import "std/io.orb";
import "binTree.orb";
# recursively calculates the sum and number of all values in a binary tree
fnc sumAndCnt (node:(BinNode cn *)) (i32 i32) {
if (== node null) {
ret (tup 0 0);
};
sym (leftRes (sumAndCnt (std.getPtr (-> node left))))
(rightRes (sumAndCnt (std.getPtr (-> node right))));
ret (tup (+ ([] leftRes 0) ([] rightRes 0) (-> node val))
(+ ([] leftRes 1) ([] rightRes 1) 1));
};
fnc printSumAndCnt (tree:(std.One BinNode)::noDrop) () {
sym (result (sumAndCnt (std.getPtr tree)));
std.println ([] result 0) ' ' ([] result 1);
};
fnc main () () {
printSumAndCnt (makeBinTree
(8
(4
2
1)
(3
1
0)));
printSumAndCnt (makeBinTree
(2
(3
1
())
(-1
0
(5
()
(1
0
4)))));
# single node tree
printSumAndCnt (makeBinTree (3 () ()));
# single node tree given as a single value
# this proves the macro works on identifiers
sym (x 8);
printSumAndCnt (makeBinTree x);
};