Index: uspace/app/bithenge/expression.c
===================================================================
--- uspace/app/bithenge/expression.c	(revision d1e580a9d87acf2fd91fe679894da1e134be946d)
+++ uspace/app/bithenge/expression.c	(revision 10334c2e815ecb663ac16f1964110930706dc263)
@@ -417,4 +417,112 @@
 }
 
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_expression_t *expr;
+	bithenge_transform_t *true_xform, *false_xform;
+} if_transform_t;
+
+static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
+{
+	return &self->base;
+}
+
+static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
+{
+	return (if_transform_t *)base;
+}
+
+static int if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
+    bool *out)
+{
+	bithenge_node_t *cond_node;
+	int rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
+	if (rc != EOK)
+		return rc;
+	if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
+		bithenge_node_dec_ref(cond_node);
+		return EINVAL;
+	}
+	*out = bithenge_boolean_node_value(cond_node);
+	bithenge_node_dec_ref(cond_node);
+	return EOK;
+}
+
+static int if_transform_apply(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
+{
+	if_transform_t *self = transform_as_if(base);
+	bool cond;
+	int rc = if_transform_choose(self, scope, &cond);
+	if (rc != EOK)
+		return rc;
+	return bithenge_transform_apply(
+	    cond ? self->true_xform : self->false_xform, scope, in, out);
+}
+
+static int if_transform_prefix_length(bithenge_transform_t *base,
+    bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
+{
+	if_transform_t *self = transform_as_if(base);
+	bool cond;
+	int rc = if_transform_choose(self, scope, &cond);
+	if (rc != EOK)
+		return rc;
+	return bithenge_transform_prefix_length(
+	    cond ? self->true_xform : self->false_xform, scope, in, out);
+}
+
+static void if_transform_destroy(bithenge_transform_t *base)
+{
+	if_transform_t *self = transform_as_if(base);
+	bithenge_expression_dec_ref(self->expr);
+	bithenge_transform_dec_ref(self->true_xform);
+	bithenge_transform_dec_ref(self->false_xform);
+	free(self);
+}
+
+static const bithenge_transform_ops_t if_transform_ops = {
+	.apply = if_transform_apply,
+	.prefix_length = if_transform_prefix_length,
+	.destroy = if_transform_destroy,
+};
+
+/** Create a transform that applies either of two transforms depending on a
+ * boolean expression. Takes references to @a expr, @a true_xform, and
+ * @a false_xform.
+ * @param[out] out Holds the new transform.
+ * @param expr The boolean expression to evaluate.
+ * @param true_xform The transform to apply if the expression is true.
+ * @param false_xform The transform to apply if the expression is false. */
+int bithenge_if_transform(bithenge_transform_t **out,
+    bithenge_expression_t *expr, bithenge_transform_t *true_xform,
+    bithenge_transform_t *false_xform)
+{
+	int rc;
+	if_transform_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
+	    0);
+	if (rc != EOK)
+		goto error;
+
+	self->expr = expr;
+	self->true_xform = true_xform;
+	self->false_xform = false_xform;
+	*out = if_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	bithenge_expression_dec_ref(expr);
+	bithenge_transform_dec_ref(true_xform);
+	bithenge_transform_dec_ref(false_xform);
+	return rc;
+}
+
 /** @}
  */
Index: uspace/app/bithenge/expression.h
===================================================================
--- uspace/app/bithenge/expression.h	(revision d1e580a9d87acf2fd91fe679894da1e134be946d)
+++ uspace/app/bithenge/expression.h	(revision 10334c2e815ecb663ac16f1964110930706dc263)
@@ -100,4 +100,6 @@
 int bithenge_param_wrapper(bithenge_transform_t **, bithenge_transform_t *,
     bithenge_expression_t **);
+int bithenge_if_transform(bithenge_transform_t **, bithenge_expression_t *,
+    bithenge_transform_t *, bithenge_transform_t *);
 
 #endif
Index: uspace/app/bithenge/script.c
===================================================================
--- uspace/app/bithenge/script.c	(revision d1e580a9d87acf2fd91fe679894da1e134be946d)
+++ uspace/app/bithenge/script.c	(revision 10334c2e815ecb663ac16f1964110930706dc263)
@@ -58,6 +58,10 @@
 
 	/* Keywords */
+	TOKEN_ELSE,
+	TOKEN_FALSE,
+	TOKEN_IF,
 	TOKEN_STRUCT,
 	TOKEN_TRANSFORM,
+	TOKEN_TRUE,
 } token_type_t;
 
@@ -204,4 +208,13 @@
 		if (!value) {
 			error_errno(state, ENOMEM);
+		} else if (!str_cmp(value, "else")) {
+			state->token = TOKEN_ELSE;
+			free(value);
+		} else if (!str_cmp(value, "false")) {
+			state->token = TOKEN_FALSE;
+			free(value);
+		} else if (!str_cmp(value, "if")) {
+			state->token = TOKEN_IF;
+			free(value);
 		} else if (!str_cmp(value, "struct")) {
 			state->token = TOKEN_STRUCT;
@@ -209,4 +222,7 @@
 		} else if (!str_cmp(value, "transform")) {
 			state->token = TOKEN_TRANSFORM;
+			free(value);
+		} else if (!str_cmp(value, "true")) {
+			state->token = TOKEN_TRUE;
 			free(value);
 		} else {
@@ -329,5 +345,23 @@
 static bithenge_expression_t *parse_expression(state_t *state)
 {
-	if (state->token == TOKEN_INTEGER) {
+	if (state->token == TOKEN_TRUE || state->token == TOKEN_FALSE) {
+		bool val = state->token == TOKEN_TRUE;
+		next_token(state);
+		bithenge_node_t *node;
+		int rc = bithenge_new_boolean_node(&node, val);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+
+		bithenge_expression_t *expr;
+		rc = bithenge_const_expression(&expr, node);
+		if (rc != EOK) {
+			error_errno(state, rc);
+			return NULL;
+		}
+
+		return expr;
+	} else if (state->token == TOKEN_INTEGER) {
 		bithenge_int_t val = state->token_int;
 		next_token(state);
@@ -454,4 +488,33 @@
 
 	return result;
+}
+
+static bithenge_transform_t *parse_if(state_t *state)
+{
+	expect(state, TOKEN_IF);
+	expect(state, '(');
+	bithenge_expression_t *expr = parse_expression(state);
+	expect(state, ')');
+	expect(state, '{');
+	bithenge_transform_t *true_xform = parse_transform(state);
+	expect(state, '}');
+	expect(state, TOKEN_ELSE);
+	expect(state, '{');
+	bithenge_transform_t *false_xform = parse_transform(state);
+	expect(state, '}');
+	if (state->error != EOK) {
+		bithenge_expression_dec_ref(expr);
+		bithenge_transform_dec_ref(true_xform);
+		bithenge_transform_dec_ref(false_xform);
+		return NULL;
+	}
+	bithenge_transform_t *if_xform;
+	int rc = bithenge_if_transform(&if_xform, expr, true_xform,
+	    false_xform);
+	if (rc != EOK) {
+		error_errno(state, rc);
+		return NULL;
+	}
+	return if_xform;
 }
 
@@ -507,4 +570,6 @@
 	if (state->token == TOKEN_IDENTIFIER) {
 		return parse_invocation(state);
+	} else if (state->token == TOKEN_IF) {
+		return parse_if(state);
 	} else if (state->token == TOKEN_STRUCT) {
 		return parse_struct(state);
Index: uspace/app/bithenge/tree.c
===================================================================
--- uspace/app/bithenge/tree.c	(revision d1e580a9d87acf2fd91fe679894da1e134be946d)
+++ uspace/app/bithenge/tree.c	(revision 10334c2e815ecb663ac16f1964110930706dc263)
@@ -126,4 +126,57 @@
 }
 
+/** Initialize an internal node.
+ * @memberof bithenge_node_t
+ * @param[out] self The node.
+ * @param[in] ops The operations provided.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_init_internal_node(bithenge_node_t *self,
+    const bithenge_internal_node_ops_t *ops)
+{
+	self->type = BITHENGE_NODE_INTERNAL;
+	self->refs = 1;
+	self->internal_ops = ops;
+	return EOK;
+}
+
+static void internal_node_indestructible(bithenge_node_t *self)
+{
+	assert(false);
+}
+
+static int empty_internal_node_for_each(bithenge_node_t *base,
+    bithenge_for_each_func_t func, void *data)
+{
+	return EOK;
+}
+
+static int empty_internal_node_get(bithenge_node_t *self, bithenge_node_t *key,
+    bithenge_node_t **out)
+{
+	return ENOENT;
+}
+
+static const bithenge_internal_node_ops_t empty_internal_node_ops = {
+	.for_each = empty_internal_node_for_each,
+	.get = empty_internal_node_get,
+	.destroy = internal_node_indestructible,
+};
+
+static bithenge_node_t empty_internal_node = {
+	BITHENGE_NODE_INTERNAL,
+	1,
+	{ .internal_ops = &empty_internal_node_ops },
+};
+
+/** Create an empty internal node.
+ * @param[out] out Holds the created node.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_empty_internal_node(bithenge_node_t **out)
+{
+	bithenge_node_inc_ref(&empty_internal_node);
+	*out = &empty_internal_node;
+	return EOK;
+}
+
 typedef struct
 {
@@ -173,18 +226,4 @@
 	.destroy = simple_internal_node_destroy,
 };
-
-/** Initialize an internal node.
- * @memberof bithenge_node_t
- * @param[out] self The node.
- * @param[in] ops The operations provided.
- * @return EOK on success or an error code from errno.h. */
-int bithenge_init_internal_node(bithenge_node_t *self,
-    const bithenge_internal_node_ops_t *ops)
-{
-	self->type = BITHENGE_NODE_INTERNAL;
-	self->refs = 1;
-	self->internal_ops = ops;
-	return EOK;
-}
 
 /** Create an internal node from a set of keys and values. This function takes
Index: uspace/app/bithenge/tree.h
===================================================================
--- uspace/app/bithenge/tree.h	(revision d1e580a9d87acf2fd91fe679894da1e134be946d)
+++ uspace/app/bithenge/tree.h	(revision 10334c2e815ecb663ac16f1964110930706dc263)
@@ -161,4 +161,5 @@
 int bithenge_init_internal_node(bithenge_node_t *,
     const bithenge_internal_node_ops_t *);
+int bithenge_new_empty_internal_node(bithenge_node_t **);
 int bithenge_new_simple_internal_node(bithenge_node_t **, bithenge_node_t **,
     bithenge_int_t, bool needs_free);
