Add recursive calls, (function), #'
diff --git a/doc/lisp-std.rst b/doc/lisp-std.rst
index 9f9dbd6..9df5ac8 100644
--- a/doc/lisp-std.rst
+++ b/doc/lisp-std.rst
@@ -138,3 +138,24 @@
         (quote cons a b)
         ; is the same as
         (list 'cons 'a 'b)
+
+.. function:: (lambda (args ...) & body)
+
+    Creates an anonymous function (closure). This function uses **lexical
+    scope** meaning that any free variables (variables bound outside this lambda
+    definition) are "captured" by the closure. You can call this function with
+    ``funcall`` (to be implemented) or ``apply``.
+
+    .. code-block:: lisp
+
+        (let1 (number 3)
+          (let1 (adds-number-to (lambda (n)
+                                  (+ n number)))
+            (print (apply adds-number-to '(5)))))
+        ; 8
+
+.. function:: (apply function (args ...))
+
+    Call ``function`` with ``args`` and return the result. Note that since this
+    is a Lisp-2 (i.e. functions and variables do not share the same namespace)
+    you need to pass a **function object** (i.e. a lambda or quoted function).
diff --git a/src/lisp/compiler.dasc b/src/lisp/compiler.dasc
index 8d96a52..9a64801 100644
--- a/src/lisp/compiler.dasc
+++ b/src/lisp/compiler.dasc
@@ -16,6 +16,7 @@
 |.arch x86;
 
 |.macro setup, nvars;
+|->function_start:
 | push ebp;
 | mov ebp, esp;
 | sub esp, (value_size * nvars);
@@ -88,7 +89,7 @@
 
 struct dasm_State *compile_function(value_t args, enum namespace namespace,
                                     struct environment *env, struct local *local_out,
-                                    struct local *local_parent, int *nargs)
+                                    struct local *local_parent, int *nargs, char *name)
 {
 	dasm_State *d;
 	dasm_State **Dst = &d;
@@ -115,15 +116,15 @@
 	local.num_stack_entries = 0;
 	local.num_closure_slots = 0;
 	local.parent = local_parent;
+	local.current_function_name = name;
 
 	dasm_growpc(&d, local.npc);
 
-	// Generate code
-	// TODO: first pass, extract bound and free variables
-
 	value_t arglist = car(args);
 	value_t body = cdr(args);
 
+	local.num_args = length(arglist);
+
 	value_t a = arglist;
 	for (int i = 0; !nilp(a); a = cdr(a), i++)
 	{
@@ -181,9 +182,10 @@
 
 		struct local local;
 		int nargs;
-		dasm_State *d = compile_function(cdr(args), namespace, env, &local, NULL, &nargs);
+		char *name = (char *)(car(args) ^ SYMBOL_TAG);
+		dasm_State *d = compile_function(cdr(args), namespace, env, &local, NULL, &nargs, name);
 
-		add_function(env, (char *)(car(args) ^ SYMBOL_TAG), link(&d),
+		add_function(env, name, link(&d),
 		             nargs, namespace);
 
 		dasm_free(&d);
@@ -394,6 +396,23 @@
 
 			compile_backquote(env, local, car(args), Dst);
 		}
+		else if (symstreq(fsym, "function"))
+		{
+			if (nargs != 1)
+			{
+				err("function should take exactly 1 argument");
+			}
+
+			if (!symbolp(car(args)))
+			{
+				err("argument to function should be a symbol resolvable at compile time");
+			}
+
+			struct function *f = find_function(env, (char *)(car(args) ^ SYMBOL_TAG));
+			value_t closure = create_closure(f->code_ptr, f->nargs, 0);
+
+			| mov eax, (closure);
+		}
 		else if (symstreq(fsym, "list"))
 		{
 			| push (nil);
@@ -420,17 +439,17 @@
 			// Compile the function with this as the parent scope
 			struct local new_local;
 			int nargs_out;
-			dasm_State *d = compile_function(args, NS_ANONYMOUS, env, &new_local, local, &nargs_out);
+			dasm_State *d = compile_function(args, NS_ANONYMOUS, env, &new_local, local, &nargs_out, "recurse");
 
 			// Link the function
 			void *func_ptr = link(&d);
 
 			// Create a closure object with the correct number of captures at
 			// runtime
-			| mov ebx, (create_closure);
 			| push (new_local.num_closure_slots);
 			| push (nargs_out);
 			| push (func_ptr);
+			| mov ebx, (create_closure);
 			| call ebx;
 			| add esp, 12;
 
@@ -448,9 +467,9 @@
 					compile_variable(find_variable(local, var->name), Dst);
 					| push eax;
 
-					| mov ebx, (set_closure_capture_variable);
 					// The capture offset
 					| push (var->number);
+					| mov ebx, (set_closure_capture_variable);
 					| call ebx;
 					// Skip the value and index
 					| add esp, 8;
@@ -466,28 +485,52 @@
 		}
 		else
 		{
-			struct function *func =
-			    find_function(env, (char *)(fsym ^ SYMBOL_TAG));
+			char *name = (char *)(fsym ^ SYMBOL_TAG);
+			struct function *func = find_function(env, name);
+			
+			bool is_recursive = false;
+			int nargs_needed = 0;
 
-			if (func == NULL)
-				err("Function undefined");
-
-			if (nargs != func->nargs)
+			if (symstreq(fsym, local->current_function_name))
 			{
-				fprintf(stderr, "Function: %s at %s:%d\n", func->name, cons_file(val), cons_line(val));
+				is_recursive = true;
+				nargs_needed = local->num_args;
+			}
+			else
+			{
+				if (func == NULL)
+				{
+					fprintf(stderr, "Function call: %s at %s:%d\n", name, cons_file(val), cons_line(val));
+					err("Function undefined");
+				}
+
+				nargs_needed = func->nargs;
+			}
+
+			if (nargs != nargs_needed)
+			{
+				fprintf(stderr, "Function call: %s at %s:%d, want %d args but given %d\n",
+					name, cons_file(val), cons_line(val), nargs_needed, nargs);
 				err("wrong number of args");
 			}
 
-			if (func->namespace == NS_FUNCTION)
+			if (is_recursive || func->namespace == NS_FUNCTION)
 			{
 				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;
+				
+				if (is_recursive)
+				{
+					| call ->function_start;
+				}
+				else
+				{
+					| mov ebx, (func->code_addr);
+					| call ebx;
+				}
 				| add esp, (nargs * value_size);
 				// result in eax
 			}
diff --git a/src/lisp/compiler.h b/src/lisp/compiler.h
index 07928d2..16cc35e 100644
--- a/src/lisp/compiler.h
+++ b/src/lisp/compiler.h
@@ -61,7 +61,11 @@
 	/// Parent environment, NULL if none (root).
 	struct local *parent;
 
-	int num_vars;
+	/// Name that the current function should be referred to by, e.g. `recurse`
+	/// for a lambda.
+	char *current_function_name;
+
+	int num_vars, num_args;
 	/// Most recently defined variable
 	struct variable *first;
 	int npc;
@@ -95,7 +99,7 @@
  */
 struct dasm_State *compile_function(value_t args, enum namespace namespace,
                                     struct environment *env, struct local *local_out,
-                                    struct local *local_parent, int *nargs);
+                                    struct local *local_parent, int *nargs, char *name);
 
 void compile_variable(struct variable *v, dasm_State *Dst);
 
diff --git a/src/lisp/lisp.c b/src/lisp/lisp.c
index b619033..c606e29 100644
--- a/src/lisp/lisp.c
+++ b/src/lisp/lisp.c
@@ -294,16 +294,20 @@
 
 	char c = is->peek(is);
 
-	if (c == '\'' || c == '`' || c == ',')
+	if (c == '\'' || c == '`' || c == ',' || c == '#')
 	{
 		is->get(is);
 
-		if (c == '`' && is->peek(is) == '@')
+		if (c == ',' && is->peek(is) == '@')
 		{
 			// This is actually a splice
 			is->get(is);
 			c = '@';
 		}
+		else if (c == '#' && is->peek(is) == '\'')
+		{
+			is->get(is);
+		}
 
 		// Read the next form and wrap it in the appropriate function
 
@@ -334,6 +338,12 @@
 		case '@':
 			symbol = symval("unquote-splice");
 			break;
+		case '#':
+			symbol = symval("function");
+			break;
+		default:
+			is->showpos(is, stderr);
+			err("Something went wrong parsing a reader macro");
 		}
 
 		*val = cons(symbol, cons(wrapped, nil));
diff --git a/src/lisp/test-closures.lisp b/src/lisp/test-closures.lisp
index 1311a98..573024d 100644
--- a/src/lisp/test-closures.lisp
+++ b/src/lisp/test-closures.lisp
@@ -1,5 +1,12 @@
+(defun mapcar (func list)
+  (if list
+    (cons (apply func (list (car list)))
+          (mapcar func (cdr list)))
+    nil))
+
+(defun double (n)
+  (+ n n))
+
 (defun main ()
-  (let1 (number 3)
-    (let1 (adds-3 (lambda (n)
-                    (+ n number)))
-      (print (apply adds-3 '(4))))))
+  (print (mapcar #'double
+                 (list 1 2 3 4 5))))