# Store a function definition
#
# Example:
#
#      f(x,y)=x^y
#
# For this definition, p1 points to the following structure.
#
#     p1
#      |
#   ___v__    ______                        ______ 
#  |CONS  |->|CONS  |--------------------->|CONS  |
#  |______|  |______|                      |______|
#      |         |                             |
#   ___v__    ___v__    ______    ______    ___v__    ______    ______
#  |SETQ  |  |CONS  |->|CONS  |->|CONS  |  |CONS  |->|CONS  |->|CONS  |
#  |______|  |______|  |______|  |______|  |______|  |______|  |______|
#                |         |         |         |         |         |
#             ___v__    ___v__    ___v__    ___v__    ___v__    ___v__
#            |SYM f |  |SYM x |  |SYM y |  |POWER |  |SYM x |  |SYM y |
#            |______|  |______|  |______|  |______|  |______|  |______|
#
# the result (in f) is a FUNCTION node
# that contains both the body and the argument list.
#
# We have
#
#	caadr(p1) points to the function name i.e. f
#	cdadr(p1) points to the arguments i.e. the list (x y)
#	caddr(p1) points to the function body i.e. (power x y)



#define F p3 # F points to the function name
#define A p4 # A points to the argument list
#define B p5 # B points to the function body

define_user_function = ->
	p3 = caadr(p1); # p3 is F
	p4 = cdadr(p1); # p4 is A
	p5 = caddr(p1); # p5 is B

	if (!issymbol(p3)) # p3 is F
		stop("function name?")

	# evaluate function body (maybe)

	if (car(p5) == symbol(EVAL))  # p5 is B
		push(cadr(p5));  # p5 is B
		Eval()
		p5 = pop();  # p5 is B

	# note how, unless explicitly forced by an eval,
	# (handled by if just above)
	# we don't eval/simplify
	# the body.
	# Why? because it's the easiest way
	# to solve scope problems i.e.
	#   x = 0
	#   f(x) = x + 1
	#   f(4) # would reply 1
	# which would need to otherwise
	# be solved by some scope device
	# somehow
	push_symbol(FUNCTION)
	push p5
	push p4
	list(3)
	p5 = pop()


	set_binding(p3, p5);  # p3 is F (function name)  # p4 is A  # p5 is B

	# return value is nil

	push_symbol(NIL)

Eval_function_reference = ->
	push p1

