from core.primitives.list import cons, car, cdr, NIL from core.primitives.symbol import symbolName, symbolKey from core.tokens import Macro from core.exceptions import syntaxError from core.tail_recursion import tailRecursion from core.macro_expand import macroExpand # from core.evaluator.naively_evaluate import naivelyEvaluate from core.evaluator.utils.getFirstN import getFirstN from core.environment import TCO def evalMacro(head, tail, environment, strict): from core.evaluator.naively_evaluate import naivelyEvaluate d = dict() 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 symbolName(firstArg) == '.': firstArg = getFirstN(args, 2)[1] arg = tail args = NIL tail = NIL else: if tail == NIL: break arg = car(tail) args = cdr(args) tail = cdr(tail) d[symbolKey(firstArg)] = arg if tail != NIL: raise syntaxError(f'extra args {repr(tail)}\nfor not variable macro {repr(head)}') expanded = macroExpand(head.body, d) if args != NIL: return Macro(args, expanded) if not TCO: return naivelyEvaluate(expanded, environment, True) ret = tailRecursion(naivelyEvaluate, expanded, environment, False) return tailRecursion.eval(ret) if strict else ret