Add "if" built-in
diff --git a/src/lisp/compiler.dasc b/src/lisp/compiler.dasc
index eac885a..e5a9444 100644
--- a/src/lisp/compiler.dasc
+++ b/src/lisp/compiler.dasc
@@ -1,13 +1,13 @@
 /* -*- mode:c -*- */
 
 #include "compiler.h"
-#include "plat/plat.h"
 #include "lib/std.h"
+#include "plat/plat.h"
 
 #include <dasm_proto.h>
 #include <dasm_x86.h>
 
-#define value_size sizeof (value_t)
+#define value_size sizeof(value_t)
 
 |.arch x86;
 
@@ -26,13 +26,13 @@
 dasm_State *d;
 unsigned int npc = 8;
 
-struct function *find_function (struct environment *env, char *name)
+struct function *find_function(struct environment *env, char *name)
 {
 	struct function *f = env->first;
 
-	while ( strcmp (f->name, name) != 0 )
+	while (strcmp(f->name, name) != 0)
 	{
-		if ( f->prev )
+		if (f->prev)
 			f = f->prev;
 		else
 			return NULL;
@@ -41,120 +41,160 @@
 	return f;
 }
 
-void compile_tl (value_t val, struct environment *env)
+void compile_tl(value_t val, struct environment *env)
 {
-	if ( !listp (val) )
-		err ("Top level must be a list");
-	
-	value_t form = car (val);
-	value_t args = cdr (val);
+	if (!listp(val))
+		err("Top level must be a list");
 
-	if ( symstreq (form, "defun") )
+	value_t form = car(val);
+	value_t args = cdr(val);
+
+	if (symstreq(form, "defun"))
 	{
 		dasm_State *d;
 		dasm_State **Dst = &d;
 
 		|.section code;
-		dasm_init (&d, DASM_MAXSECTION);
-		
+		dasm_init(&d, DASM_MAXSECTION);
+
 		|.globals lbl_;
-		void *labels[ lbl__MAX ];
-		dasm_setupglobal (&d, labels, lbl__MAX);
-		
+		void *labels[lbl__MAX];
+		dasm_setupglobal(&d, labels, lbl__MAX);
+
 		|.actionlist lisp_actions;
-		dasm_setup (&d, lisp_actions);
-		
-		dasm_growpc (&d, npc);
+		dasm_setup(&d, lisp_actions);
+
+		dasm_growpc(&d, npc);
 
 		struct local local;
 		local.first = NULL;
 		local.num_vars = 0;
-	
+
 		// Generate code
-		
+
 		| setup 0;
-		
-		value_t name = car (args);
-		args = cdr (args);
-		value_t arglist = car (args);
-		value_t body = cdr (args);
 
-		if ( (name & HEAP_MASK) != SYMBOL_TAG )
-			err ("function name must be a symbol");
+		value_t name = car(args);
+		args = cdr(args);
+		value_t arglist = car(args);
+		value_t body = cdr(args);
 
-		for ( ; !nilp (body); body = cdr (body) )
+		if ((name & HEAP_MASK) != SYMBOL_TAG)
+			err("function name must be a symbol");
+
+		for (; !nilp(body); body = cdr(body))
 		{
-			compile_expression (env, &local, car (body), Dst);
+			compile_expression(env, &local, car(body), Dst);
 		}
 
 		| cleanup;
 
-		add_function (env, (char *) (name ^ SYMBOL_TAG), link (Dst), length (arglist));
+		add_function(env, (char *)(name ^ SYMBOL_TAG), link(Dst),
+		             length(arglist));
 
-		dasm_free (&d);
+		dasm_free(&d);
 	}
 }
 
-struct environment compile_all (struct istream *is)
+struct environment compile_all(struct istream *is)
 {
 	value_t val;
 	struct environment env;
 	env.first = NULL;
-	load_std (&env);
-	
-	while ( read1 (is, &val) )
+	load_std(&env);
+
+	while (read1(is, &val))
 	{
-		compile_tl (val, &env);
+		compile_tl(val, &env);
 	}
 
 	return env;
 }
 
-void compile_expression (struct environment *env, struct local *local,
-                         value_t val, dasm_State **Dst)
+int nextpc(struct local *local, dasm_State **Dst)
 {
-	if ( integerp (val) || stringp (val) || symbolp (val) )
+	int n = local->nextpc++;
+	if (n > local->npc)
+	{
+		local->npc += 16;
+		dasm_growpc(Dst, local->npc);
+	}
+	return n;
+}
+
+void compile_expression(struct environment *env, struct local *local,
+                        value_t val, dasm_State **Dst)
+{
+	if (symstreq(val, "nil"))
+	{
+		| mov eax, (nil);
+	}
+	else if (integerp(val) || stringp(val) || symbolp(val))
 	{
 		| mov eax, val;
 	}
-	else if ( listp (val) )
+	else if (listp(val))
 	{
-		value_t fsym = car (val);
+		value_t fsym = car(val);
+		value_t args = cdr(val);
+		int nargs = length(args);
 
-		if ( !symbolp (fsym) )
+		if (!symbolp(fsym))
 		{
-			err ("function name must be a symbol");
+			err("function name must be a symbol");
 		}
 
-		struct function *func = find_function (env, (char *) (fsym ^ SYMBOL_TAG));
-		value_t args = cdr (val);
-		int nargs = length (args);
-
-		if ( nargs != func->nargs )
-			err ("wrong number of args");
-
-		for ( int i = length (args) - 1; i >= 0; i-- )
+		if (symstreq(fsym, "if"))
 		{
-			compile_expression (env, local, elt (args, i), Dst);
-			| push eax;
-		}
+			if (nargs < 2 || nargs > 3)
+				err("Must give at least 2 arguments to if");
 
-		| mov ebx, (func->code_addr);
-		| call ebx;
-		| add esp, (nargs * 4);
-		// result in eax
+			compile_expression(env, local, car(args), Dst);
+			int false_label = nextpc(local, Dst),
+			    after_label = nextpc(local, Dst);
+
+			// result is in eax
+			| cmp eax, (nil);
+			| je =>false_label;
+
+			compile_expression(env, local, elt(args, 1), Dst);
+
+			|=>false_label:
+			if (nargs == 3)
+			    compile_expression(env, local, elt(args, 2), Dst);
+			|=>after_label:
+		}
+		else
+		{
+			struct function *func =
+			    find_function(env, (char *)(fsym ^ SYMBOL_TAG));
+
+			if (nargs != func->nargs)
+				err("wrong number of args");
+
+			for (int i = length(args) - 1; i >= 0; i--)
+			{
+				compile_expression(env, local, elt(args, i), Dst);
+				| push eax;
+			}
+
+			| mov ebx, (func->code_addr);
+			| call ebx;
+			| add esp, (nargs * 4);
+			// result in eax
+		}
 	}
 }
 
-void compile_expr_to_func (struct environment *env, char *name, value_t val,
-                           dasm_State **Dst)
+void compile_expr_to_func(struct environment *env, char *name, value_t val,
+                          dasm_State **Dst)
 {
 	| setup 0;
 
 	struct local local;
-	compile_expression (env, &local, val, Dst);
-	
+	compile_expression(env, &local, val, Dst);
+
 	| cleanup;
 
-	add_function (env, name, link (Dst), 0);
+	add_function(env, name, link(Dst), 0);
 }