def quasiquote_evaluate(cls, expr: Expression, frame: Frame, gui_holder: Holder, splicing=False): is_well_formed = False if isinstance(expr, Pair): try: lst = pair_to_list(expr) except OperandDeduceError: pass else: is_well_formed = (not any( map((lambda x: (isinstance(x, Symbol) and (x.value in ['unquote', 'quasiquote', 'unquote-splicing']))), lst))) visual_expression = VisualExpression(expr) gui_holder.link_visual(visual_expression) if (not is_well_formed): visual_expression.children[2:] = [] if isinstance(expr, Pair): if (isinstance(expr.first, Symbol) and (expr.first.value in ('unquote', 'unquote-splicing'))): if ((expr.first.value == 'unquote-splicing') and (not splicing)): raise OperandDeduceError( 'Unquote-splicing must be in list template.') gui_holder.evaluate() verify_exact_callable_length(expr.first, 1, (len(pair_to_list(expr)) - 1)) out = evaluate(expr.rest.first, frame, visual_expression.children[1]) visual_expression.value = out gui_holder.complete() return out elif (isinstance(expr.first, Symbol) and (expr.first.value == 'quasiquote')): visual_expression.value = expr gui_holder.complete() return expr else: if is_well_formed: out = [] for (sub_expr, holder) in zip(pair_to_list(expr), visual_expression.children): splicing = (isinstance(sub_expr, Pair) and isinstance(sub_expr.first, Symbol) and (sub_expr.first.value == 'unquote-splicing')) evaluated = Quasiquote.quasiquote_evaluate( sub_expr, frame, holder, splicing) if splicing: if (not isinstance(evaluated, (Pair, NilType))): raise TypeMismatchError(''.join([ 'Can only splice lists, not ', '{}'.format(evaluated), '.' ])) out.extend(pair_to_list(evaluated)) else: out.append(evaluated) out = make_list(out) else: if (not logger.dotted): raise OperandDeduceError(''.join([ '{}'.format(expr), ' is an ill-formed quasiquotation.' ])) out = Pair( Quasiquote.quasiquote_evaluate( expr.first, frame, visual_expression.children[0]), Quasiquote.quasiquote_evaluate( expr.rest, frame, visual_expression.children[1])) visual_expression.value = out gui_holder.complete() return out else: visual_expression.value = expr gui_holder.complete() return expr
def evaluate(expr: Expression, frame: Frame, gui_holder: log.Holder, tail_context: bool = False, *, log_stack: bool = True) -> Union[(Expression, Thunk)]: '\n >>> global_frame = __import__("special_forms").build_global_frame()\n >>> gui_holder = __import__("gui").Holder(None)\n >>> __import__("gui").Root.setroot(gui_holder)\n >>> __import__("gui").silent = True\n\n >>> buff = __import__("lexer").TokenBuffer(["(+ 1 2)"])\n >>> expr = __import__("parser").get_expression(buff)\n >>> result = evaluate(expr, global_frame, gui_holder)\n >>> print(result)\n 3\n >>> evaluate(__import__("parser").get_expression(__import__("lexer").TokenBuffer(["(+ 3 4 5)"])), global_frame, gui_holder)\n 12\n >>> evaluate(__import__("parser").get_expression(__import__("lexer").TokenBuffer(["(* 3 4 5)"])), global_frame, gui_holder)\n 60\n >>> evaluate(__import__("parser").get_expression(__import__("lexer").TokenBuffer(["(* (+ 1 2) 4 5)"])), global_frame, gui_holder)\n 60\n >>> __import__("gui").silent = False\n ' depth = 0 thunks = [] holders = [] while True: if (depth > RECURSION_LIMIT): raise OutOfMemoryError( 'Debugger ran out of memory due to excessively deep recursion.' ) if isinstance(gui_holder.expression, Expression): visual_expression = log.VisualExpression(expr) gui_holder.link_visual(visual_expression) else: visual_expression = gui_holder.expression if log_stack: log.logger.eval_stack.append(''.join([ '{}'.format(repr(expr)), ' [frame = ', '{}'.format(frame.id), ']' ])) depth += 1 holders.append(gui_holder) if (isinstance(expr, Number) or isinstance(expr, Callable) or isinstance(expr, Boolean) or isinstance(expr, String) or isinstance(expr, Promise)): ret = expr elif isinstance(expr, Symbol): gui_holder.evaluate() ret = frame.lookup(expr) elif isinstance(expr, Pair): if tail_context: if log_stack: log.logger.eval_stack.pop() return Thunk(expr, frame, gui_holder, log_stack) else: gui_holder.evaluate() operator = expr.first import environment if (isinstance(operator, Symbol) and environment.get_special_form(operator.value)): operator = environment.get_special_form(operator.value) else: operator = evaluate(operator, frame, visual_expression.children[0]) operands = pair_to_list(expr.rest) out = apply(operator, operands, frame, gui_holder) if isinstance(out, Thunk): (expr, frame) = (out.expr, out.frame) gui_holder = out.gui_holder thunks.append(out) continue ret = out elif ((expr is Nil) or (expr is Undefined)): ret = expr else: raise Exception('Internal error. Please report to maintainer!') for _ in range(depth): log.logger.eval_stack.pop() for (thunk, holder) in zip(reversed(thunks), reversed(holders)): holder.expression.value = ret holder.complete() thunk.evaluate(ret) holders[0].expression.value = ret holders[0].complete() return ret