from core.primitives.list import NIL, cons, car, cdr from core.primitives.symbol import isSymbol, symbolName from core.exceptions import syntaxError from core.tokens import Lambda from core.tail_recursion import tailRecursion # from core.evaluator.naively_evaluate import naivelyEvaluate from core.evaluator.utils.getFirstN import getFirstN from core.environment import TCO def evalCall(head, tail, environment, environmentParent, strict): from core.evaluator.naively_evaluate import naivelyEvaluate args = head.args if args == NIL and tail != NIL: raise syntaxError(f'more than zero args for {repr(head)}') while args != NIL: firstArg = car(args) if not isSymbol(firstArg): raise syntaxError(f'cannot take non-symbol as argument: {repr(firstArg)}') if symbolName(firstArg) == '.': firstArg = getFirstN(args, 2)[1] arr = [] while tail != NIL: arr.append(naivelyEvaluate(car(tail), environmentParent, True)) tail = cdr(tail) arg = NIL for elem in reversed(arr): arg = cons(elem, arg) args = NIL else: if tail == NIL: break arg = naivelyEvaluate(car(tail), environmentParent, True) args = cdr(args) tail = cdr(tail) environment.add(firstArg, arg) if tail != NIL: raise syntaxError(f'extra args {repr(tail)}\nfor not variable lambda {repr(head)}') if args != NIL: return Lambda(args, head.body, environment) if not TCO: return naivelyEvaluate(head.body, environment, True) ret = tailRecursion(naivelyEvaluate, head.body, environment, False) return tailRecursion.eval(ret) if strict else ret