+ if (!sym_next(&i)) {
+ if (type & clType_user) {
+ uid_t u = *(uid_t *)b->name;
+ sym_destroyTable(&l->v.t);
+ l->type = (l->type & ~clNode_mask) | clNode_immed;
+ l->v.u = u;
+ } else {
+ char *s = xstrdup(b->name);
+ sym_destroyTable(&l->v.t);
+ l->type = (l->type & ~clNode_mask) | clNode_immed;
+ l->v.s = s;
+ }
+ }
+ }
+
+ /* --- Done --- */
+
+ return (l);
+ }
+
+ /* --- Unfriendly nodes --- *
+ *
+ * Create a binop node and return that. If @l@ is a binop node, and @r@
+ * isn't, and the operation isn't set difference (i.e., it's commutative)
+ * then swap the two over to lessen the depth of recursion later.
+ */
+
+ else {
+ class_node *c = xmalloc(sizeof(*c));
+
+ c->type = type | op;
+ c->ref = 1;
+ if (lnode >= clNode_binop && rnode < clNode_binop && op != clNode_diff) {
+ c->v.c.l = r;
+ c->v.c.r = l;
+ } else {
+ c->v.c.l = l;
+ c->v.c.r = r;
+ }
+ return (c);
+ }
+}
+
+/* --- @class_union@ --- *
+ *
+ * Arguments: @class_node *l@ = left argument
+ * @class_node *r@ = right argument
+ *
+ * Returns: A class node representing the union of the two classes.
+ *
+ * Use: Performs the union operation on classes. If the types don't
+ * match, then a null pointer is returned. Both @l@ and @r@
+ * may be modified, and will be decremented before they get
+ * returned to you. If you don't want that to happen, ensure
+ * that you've claimed a reference to the original versions.
+ */
+
+class_node *class_union(class_node *l, class_node *r)
+{
+ /* --- Check for the really simple cases --- */
+
+ if (l == class_all || r == class_all) {
+ class_dec(l);
+ class_dec(r);
+ return (class_all);
+ }
+
+ if (l == class_none)
+ return (r);
+ if (r == class_none)
+ return (l);
+
+ /* --- Do the job --- */
+
+ return (class__binop(l, r, clNode_union));
+}
+
+/* --- @class_diff@ --- *
+ *
+ * Arguments: @class_node *l@ = left argument
+ * @class_node *r@ = right argument
+ *
+ * Returns: A class node representing the difference of the two classes.
+ *
+ * Use: Performs the set difference operation on classes. If the
+ * types don't match, then a null pointer is returned. Both
+ * @l@ and @r@ may be modified, and will be decremented before
+ * they get returned to you. If you don't want that to happen,
+ * ensure that you've claimed a reference to the original
+ * versions.
+ */
+
+class_node *class_diff(class_node *l, class_node *r)
+{
+ /* --- Check for the really simple cases --- */
+
+ if (l == class_none || r == class_all) {
+ class_dec(l);
+ class_dec(r);
+ return (class_none);
+ }
+
+ if (r == class_none)
+ return (l);
+
+ /* --- Do the job --- */
+
+ return (class__binop(l, r, clNode_diff));
+}
+
+/* --- @class_isect@ --- *
+ *
+ * Arguments: @class_node *l@ = left argument
+ * @class_node *r@ = right argument
+ *
+ * Returns: A class node representing the intersection of the two
+ * classes.
+ *
+ * Use: Performs the intersecion operation on classes. If the types
+ * don't match, then a null pointer is returned. Both @l@ and
+ * @r@ may be modified, and will be decremented before they get
+ * returned to you. If you don't want that to happen, ensure
+ * that you've claimed a reference to the original versions.
+ */