func conditionalStatement(env *Env, name string, args []Sexp) Sexp {
	thunk, isThunk := args[len(args)-1].(SexpSymbol)
	args = args[:len(args)-1]
	if !isThunk {
		log.Fatal("Error passing thunk into conditional statement")
	}
	allowThunk := thunk.ofType == TRUE
	var condition bool
	var toReturn Sexp
	switch i := args[0].(type) {
	case SexpFloat, SexpInt:
		condition = true
	case SexpPair:
		if i.head == nil {
			condition = false
		} else {
			condition = true
		}
	case SexpSymbol:
		if i.ofType == FALSE {
			condition = false
		} else {
			condition = true
		}
	default:
		fmt.Println(i)
		log.Fatal("Error trying to interpret condition for if statement")
	}
	if condition {
		toReturn = args[1].Eval(env, &StackFrame{}, allowThunk)
	} else {
		if len(args) > 2 && args[2] != nil {
			toReturn = args[2].Eval(env, &StackFrame{}, allowThunk)
		} else {
			toReturn = SexpSymbol{ofType: FALSE, value: "nil"}
		}
	}
	return toReturn
}
***** handle conditional statements ********
package lispy
import (
	"bufio"
	"fmt"
	"log"
	"math"
	"math/rand"
	"os"
	"reflect"
	"strconv"
	"time"
)
type LispyUserFunction func(env *Env, name string, args []Sexp) Sexp
type FunctionThunkValue struct {
	env      *Env
	function FunctionValue
}
func (thunk FunctionThunkValue) String() string {
	return fmt.Sprintf("function thunk: %s", thunk.function)
}
func (thunk FunctionThunkValue) Eval(env *Env, frame *StackFrame, allowThunk bool) Sexp {
	return nil
}
func varDefinition(env *Env, key string, args []Sexp) Sexp {
	value := args[0].Eval(env, &StackFrame{}, false)
	env.store[key] = value
	return value
}
func getVarBinding(env *Env, key string, args []Sexp) Sexp {
	if v, found := env.store[key]; found {
		value, ok := v.(Sexp)
		if !ok {
			return SexpPair{}
		}
		return value
	} else if env.parent != nil {
		return getVarBinding(env.parent, key, args)
	}
	log.Fatal("Error, ", key, " has not previously been defined!")
	return nil
}
func (funcVal FunctionValue) Eval(env *Env, frame *StackFrame, allowThunk bool) Sexp {
	name := frame.args[len(frame.args)-1].String()
	env.store[name] = funcVal
	dec(env)
	list := []Sexp{SexpSymbol{ofType: STRING, value: funcVal.defn.name}, funcVal.defn.arguments, funcVal.defn.body}
	return makeSList(list)
}
func evalFunc(env *Env, s *SexpFunctionCall, allowThunk bool) Sexp {
	name := s.name
	node, isFuncLiteral := env.store[name].(FunctionValue)
	if !isFuncLiteral {
		node, isFuncLiteral = getVarBinding(env, name, []Sexp{}).(FunctionValue)
		if !isFuncLiteral {
			log.Fatal("Error, badly defined function trying to be called: ", s.name)
		}
	}
	newExprs := make([]Sexp, 0)
	if node.defn.macro {
		macroArgs := s.arguments
		switch i := s.arguments.head.(type) {
		case SexpPair:
			quote, isQuote := i.head.(SexpSymbol)
			if isQuote && quote.value == "" {
				pair, isPair := i.tail.(SexpPair)
				if isPair {
					macroArgs = pair
				}
			}
		}
		env.store[node.defn.arguments.value[0].String()] = macroArgs
		macroRes := node.defn.body.Eval(env, &StackFrame{}, false)
		finalRes := macroRes.Eval(env, &StackFrame{}, allowThunk)
		return finalRes
	}
	if s.arguments.head != nil {
		if name == "quote" {
			newExprs = makeList(s.arguments)
		} else {
			for _, toEvaluate := range makeList(s.arguments) {
				if toEvaluate != nil {
					evaluatedArg := toEvaluate.Eval(env, &StackFrame{}, false)
					newExprs = append(newExprs, evaluatedArg)
				}
			}
		}
	}
	variableNumberOfArgs := false
	for i, arg := range node.defn.arguments.value {
		if arg.String() == "&" {
			env.store[node.defn.arguments.value[i+1].String()] = makeSList(newExprs[i:])
			variableNumberOfArgs = true
			break
		} else {
			env.store[arg.String()] = newExprs[i]
		}
	}
	if len(node.defn.arguments.value) != len(newExprs) && node.defn.userfunc == nil && !variableNumberOfArgs {
		fmt.Println(len(node.defn.arguments.value), newExprs)
		log.Fatal("Incorrect number of arguments passed in to ", node.defn.name)
	}
	if node.defn.userfunc != nil && node.defn.body == nil {
		return node.defn.userfunc(env, name, newExprs)
	}
	functionThunk := FunctionThunkValue{env: env, function: node}
	if allowThunk {
		return functionThunk
	}
	return unwrapThunks(functionThunk)
}
func unwrapThunks(functionThunk FunctionThunkValue) Sexp {
	isTail := true
	var funcResult Sexp
	for isTail {
		funcResult = functionThunk.function.defn.body.Eval(functionThunk.env, &StackFrame{}, true)
		functionThunk, isTail = funcResult.(FunctionThunkValue)
	}
	return funcResult
}
func makeUserFunction(name string, function LispyUserFunction) FunctionValue {
	var sfunc SexpFunctionLiteral
	sfunc.name = name
	sfunc.userfunc = function
	return FunctionValue{defn: &sfunc}
}
func createList(env *Env, name string, args []Sexp) Sexp {
	i := unwrapSList(args)
	if i == nil {
		return SexpPair{}
	}
	return i
}
func quote(env *Env, name string, args []Sexp) Sexp {
	return args[0]
}
func unwrapSList(expressions []Sexp) Sexp {
	if len(expressions) == 0 {
		return nil
	}
	switch i := expressions[0].(type) {
	case SexpPair:
		if i.tail == nil {
			return consHelper(i.head, unwrapSList(expressions[1:]))
		}
	}
	return consHelper(expressions[0], unwrapSList(expressions[1:]))
}
func unwrap(arg Sexp) SexpPair {
	pair1, isPair1 := arg.(SexpPair)
	if !isPair1 {
		switch i := arg.(type) {
		case SexpInt, SexpFloat, SexpArray, SexpSymbol, FunctionValue:
			return SexpPair{head: SexpPair{head: i, tail: nil}, tail: nil}
		case SexpFunctionLiteral:
			argList := makeSList(i.arguments.value)
			list := makeSList([]Sexp{SexpSymbol{ofType: STRING, value: i.name}, argList, i.body})
			listPair, _ := list.(SexpPair)
			return listPair
		default:
			fmt.Println(reflect.TypeOf(arg), arg)
			log.Fatal("Error unwrapping for built in functions")
		}
	}
	return SexpPair{head: pair1, tail: nil}
}
func car(env *Env, name string, args []Sexp) Sexp {
	if len(args) == 0 {
		log.Fatal("Uh oh, you need to pass an argument to car")
	}
	pair1 := unwrap(args[0])
	switch i := pair1.head.(type) {
	case SexpPair:
		return i.head
	case SexpInt, SexpFloat, SexpSymbol, SexpArray:
		return i
	default:
		return nil
	}
}
func cdr(env *Env, name string, args []Sexp) Sexp {
	if len(args) == 0 {
		log.Fatal("Uh oh, you need to pass an argument to car")
	}
	pair1 := unwrap(args[0])
	switch i := pair1.head.(type) {
	case SexpPair:
		if i.tail == nil {
			return SexpPair{}
		}
		return i.tail
	case SexpInt, SexpFloat, SexpSymbol:
		if pair1.tail == nil {
			return SexpPair{}
		}
		return pair1.tail
	default:
		fmt.Println(reflect.TypeOf(i))
		log.Fatal("argument 0 of cdr has wrong type!")
	}
	return nil
}
func cons(env *Env, name string, args []Sexp) Sexp {
	if len(args) < 2 {
		log.Fatal("Incorrect number of arguments!")
	}
	list := unwrap(args[1])
	newHead := consHelper(args[0], list.head)
	return newHead
}
func consHelper(a Sexp, b Sexp) SexpPair {
	return SexpPair{a, b}
}
func isQuote(env *Env, name string, args []Sexp) Sexp {
	if len(args) == 0 {
		log.Fatal("Error checking quote type")
	}
	switch i := args[0].(type) {
	case SexpSymbol:
		if i.ofType == QUOTE || i.value == "quote" {
			return SexpSymbol{ofType: TRUE, value: "true"}
		}
	}
	return SexpSymbol{ofType: FALSE, value: "false"}
}
func swap(env *Env, name string, args []Sexp) Sexp {
	if len(args) == 0 {
		log.Fatal("Error trying to swap element")
	}
	list, isList := args[0].(SexpPair)
	if !isList {
		log.Fatal("Error trying to parse arguments of swap")
	}
	newList, isNewList := list.tail.(SexpPair)
	if !isNewList {
		log.Fatal("Error swapping non-list!")
	}
	fmt.Println(list.head.String())
	newVal := newList.head.Eval(env, &StackFrame{}, false)
	setValWhileKeyExists(env, list.head.String(), newVal)
	return newVal
}
func setValWhileKeyExists(env *Env, key string, val Value) {
	if _, found := env.store[key]; found {
		env.store[key] = val
		if env.parent != nil {
			setValWhileKeyExists(env.parent, key, val)
		}
	}
}
func readstring(env *Env, name string, args []Sexp) Sexp {
	if len(args) < 1 {
		log.Fatal("Error trying to read object from tring!")
	}
	stringObj, isString := args[0].(SexpSymbol)
	if !isString || stringObj.ofType != STRING {
		log.Fatal("Error trying to read an object from a non-string!")
	}
	res, err := evalHelper(stringObj.value)
	if err != nil {
		log.Fatal("Error trying to parse an object from a string !")
	}
	return res[0]
}
func readline(env *Env, name string, args []Sexp) Sexp {
	if len(args) > 0 {
		fmt.Print(args[0].String())
	}
	scanner := bufio.NewScanner(os.Stdin)
	var val string
	if scanner.Scan() {
		val = scanner.Text()
	}
	return SexpSymbol{ofType: STRING, value: val}
}
func str(env *Env, name string, args []Sexp) Sexp {
	val := ""
	for _, arg := range args {
		val += arg.String()
	}
	return SexpSymbol{ofType: STRING, value: val}
}