def execute(self, operands: List[Expression], frame: Frame, gui_holder: Holder, eval_operands=True) -> Expression: if eval_operands: operands = evaluate_all( operands, frame, gui_holder.expression.children[1:]) gui_holder.expression.set_entries([]) gui_holder.apply() return self.execute_evaluated(operands, frame)
def execute(self, operands: List[Expression], frame: Frame, gui_holder: Holder, eval_operands=True): verify_exact_callable_length(self, 1, len(operands)) operand = operands[0] if eval_operands: operand = evaluate_all(operands, frame, gui_holder.expression.children[1:])[0] if not isinstance(operand, Promise): raise OperandDeduceError( f"Force expected a Promise, received {operand}") if operand.forced: return operand.expr if logger.fragile: raise IrreversibleOperationError() gui_holder.expression.set_entries([ VisualExpression(operand.expr, gui_holder.expression.display_value) ]) gui_holder.apply() evaluated = evaluate(operand.expr, operand.frame, gui_holder.expression.children[0]) if not logger.dotted and not isinstance(evaluated, (Pair, NilType)): raise TypeMismatchError( f"Unable to force a Promise evaluating to {operand.expr}, expected another Pair or Nil" ) operand.expr = evaluated operand.force() return operand.expr
def execute(self, operands: List[Expression], frame: Frame, gui_holder: Holder, eval_operands=True): verify_exact_callable_length(self, 1, len(operands)) if eval_operands: operands = evaluate_all(operands, frame, gui_holder.expression.children[1:]) if (not isinstance(operands[0], Symbol)): raise OperandDeduceError(''.join([ 'Load expected a Symbol, received ', '{}'.format(operands[0]), '.' ])) if logger.fragile: raise IrreversibleOperationError() try: with open(''.join(['{}'.format(operands[0].value), '.scm'])) as file: code = (('(begin' + '\n'.join(file.readlines())) + '\n)') buffer = TokenBuffer([code]) expr = get_expression(buffer) gui_holder.expression.set_entries([ VisualExpression(expr, gui_holder.expression.display_value) ]) gui_holder.apply() return evaluate(expr, frame, gui_holder.expression.children[0], True) except OSError as e: raise LoadError(e)
def execute(self, operands: List[Expression], frame: Frame, gui_holder: Holder, eval_operands=True): verify_exact_callable_length(self, 1, len(operands)) if eval_operands: operands = evaluate_all(operands, frame, gui_holder.expression.children[1:]) if not isinstance(operands[0], Symbol): raise OperandDeduceError( f"Load expected a Symbol, received {operands[0]}.") if logger.fragile: raise IrreversibleOperationError() try: with open(f"{operands[0].value}.scm") as file: code = "(begin-noexcept" + "\n".join(file.readlines()) + "\n)" buffer = TokenBuffer([code]) expr = get_expression(buffer) gui_holder.expression.set_entries([ VisualExpression(expr, gui_holder.expression.display_value) ]) gui_holder.apply() return evaluate(expr, frame, gui_holder.expression.children[0], True) except OSError as e: raise LoadError(e)
def execute(self, operands: List[Expression], frame: Frame, gui_holder: Holder, eval_operands=True): verify_exact_callable_length(self, 1, len(operands)) if eval_operands: operand = evaluate(operands[0], frame, gui_holder.expression.children[1]) else: operand = operands[0] gui_holder.expression.set_entries([VisualExpression(operand, gui_holder.expression.display_value)]) gui_holder.apply() return evaluate(operand, frame, gui_holder.expression.children[0], True)
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 = gui_holder.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(f"Can only splice lists, not {evaluated}.") out.extend(pair_to_list(evaluated)) else: out.append(evaluated) out = make_list(out) else: if not logger.dotted: raise OperandDeduceError(f"{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 execute(self, operands: List[Expression], frame: Frame, gui_holder: Holder, eval_operands=True): verify_exact_callable_length(self, 2, len(operands)) if eval_operands: operands = evaluate_all(operands, frame, gui_holder.expression.children[1:]) func, args = operands if not isinstance(func, Applicable): raise OperandDeduceError(f"Unable to apply {func}.") gui_holder.expression.set_entries([VisualExpression(Pair(func, args), gui_holder.expression.display_value)]) gui_holder.expression.children[0].expression.children = [] gui_holder.apply() args = pair_to_list(args) return func.execute(args, frame, gui_holder.expression.children[0], False)
def execute(self, operands: List[Expression], frame: Frame, gui_holder: Holder, eval_operands=True): new_frame = Frame(self.name, self.frame if self.lexically_scoped else frame) if eval_operands and self.evaluates_operands: operands = evaluate_all(operands, frame, gui_holder.expression.children[1:]) if self.var_param: verify_min_callable_length(self, len(self.params), len(operands)) else: verify_exact_callable_length(self, len(self.params), len(operands)) if len(self.body) > 1: body = [Pair(Symbol("begin"), make_list(self.body))] else: body = self.body for param, value in zip(self.params, operands): new_frame.assign(param, value) if self.var_param: new_frame.assign(self.var_param, make_list(operands[len(self.params):])) out = None gui_holder.expression.set_entries([ VisualExpression(expr, gui_holder.expression.display_value) for expr in body ]) gui_holder.apply() for i, expression in enumerate(body): out = evaluate(expression, new_frame, gui_holder.expression.children[i], self.evaluates_operands and i == len(body) - 1, log_stack=len(self.body) == 1) new_frame.assign(return_symbol, out) if not self.evaluates_operands: gui_holder.expression.set_entries( [VisualExpression(out, gui_holder.expression.display_value)]) out = evaluate(out, frame, gui_holder.expression.children[i], True) return out
def execute(self, operands: List[Expression], frame: Frame, gui_holder: Holder, eval_operands=True): verify_exact_callable_length(self, 1, len(operands)) if eval_operands: operands = evaluate_all(operands, frame, gui_holder.expression.children[1:]) if not isinstance(operands[0], String): raise OperandDeduceError(f"Load expected a String, received {operands[0]}.") if logger.fragile: raise IrreversibleOperationError() from os import listdir from os.path import join directory = operands[0].value try: targets = sorted(listdir(directory)) targets = [join(directory, target) for target in targets if target.endswith(".scm")] exprs = [make_list([Symbol("load"), make_list([Symbol("quote"), Symbol(x[:-4])])]) for x in targets] equiv = make_list([Symbol("begin-noexcept")] + exprs) gui_holder.expression.set_entries([equiv]) gui_holder.apply() return evaluate(equiv, frame, gui_holder.expression.children[0], True) except Exception as e: raise SchemeError(e)
def evaluate(expr: Expression, frame: Frame, gui_holder: log.Holder, tail_context: bool = False, *, log_stack: bool=True) -> Union[Expression, Thunk]: depth = 0 thunks = [] holders = [] while True: if depth > RECURSION_LIMIT: raise OutOfMemoryError("Debugger ran out of memory due to excessively deep recursion.") visual_expression = gui_holder.expression if log_stack: log.logger.eval_stack.append(f"{repr(expr)} [frame = {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 thunks.append(out) if out.gui_holder.state != log.HolderState.EVALUATING: out.gui_holder.evaluate() if log.logger.show_thunks: gui_holder = out.gui_holder else: gui_holder.expression.display_value = out.gui_holder.expression.display_value gui_holder.expression.base_expr = out.gui_holder.expression.base_expr gui_holder.expression.set_entries(list(x.expression for x in out.gui_holder.expression.children)) 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
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 string_exec(strings, out, visualize_tail_calls, global_frame=None): import log empty = False if global_frame is None: empty = True from environment import build_global_frame log.logger.f_delta -= 1 global_frame = build_global_frame() log.logger.active_frames.pop(0) # clear builtin frame log.logger.f_delta += 1 log.logger.global_frame = log.logger.frame_lookup[id(global_frame)] log.logger.graphics_lookup[id(global_frame)] = Canvas() log.logger.export_states = [] log.logger.roots = [] log.logger.frame_updates = [] log.logger._out = [] log.logger.visualize_tail_calls(visualize_tail_calls) for i, string in enumerate(strings): try: if not string.strip(): continue buff = TokenBuffer([string]) while not buff.done: expr = get_expression(buff) if expr is None: continue empty = False log.logger.new_expr() holder = Holder(expr, None) Root.setroot(holder) res = evaluate(expr, global_frame, holder) if res is not Undefined: out(res) if not log.logger.fragile and log.logger.autodraw: try: log.logger.raw_out("AUTODRAW" + json.dumps([log.logger.i, log.logger.heap.record(res)]) + "\n") except RecursionError: pass except (SchemeError, ZeroDivisionError, RecursionError, ValueError) as e: if isinstance(e, ParseError): log.logger.new_expr() raise if not log.logger.fragile: log.logger.raw_out("Traceback (most recent call last)\n") for j, expr in enumerate(log.logger.eval_stack[:MAX_TRACEBACK_LENGTH - 1]): log.logger.raw_out(str(j).ljust(3) + " " + expr + "\n") truncated = len(log.logger.eval_stack) - MAX_TRACEBACK_LENGTH if len(log.logger.eval_stack) > MAX_TRACEBACK_LENGTH: log.logger.raw_out(f"[{truncated} lines omitted from traceback]\n") log.logger.raw_out( str(len(log.logger.eval_stack) - 1).ljust(3) + " " + log.logger.eval_stack[-1] + "\n" ) log.logger.out(e) except TimeLimitException: if not log.logger.fragile: log.logger.out("Time limit exceeded.") log.logger.new_expr() if empty: log.logger.new_expr() holder = Holder(Undefined, None) Root.setroot(holder) evaluate(Undefined, global_frame, holder) log.logger.new_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
def string_exec(strings, out, global_frame=None): import log empty = False if (global_frame is None): empty = True from environment import build_global_frame log.logger.f_delta -= 1 global_frame = build_global_frame() log.logger.active_frames.pop(0) log.logger.f_delta += 1 log.logger.global_frame = log.logger.frame_lookup[id(global_frame)] log.logger.graphics_lookup[id(global_frame)] = Canvas() log.logger.export_states = [] log.logger.roots = [] log.logger.frame_updates = [] log.logger._out = [] for (i, string) in enumerate(strings): try: if (not string.strip()): continue buff = TokenBuffer([string]) while (not buff.done): expr = get_expression(buff) if (expr is None): continue empty = False log.logger.new_expr() holder = Holder(expr, None) Root.setroot(holder) res = evaluate(expr, global_frame, holder) if (res is not Undefined): out(res) if ((not log.logger.fragile) and log.logger.autodraw and isinstance(res, Pair)): log.logger.raw_out((('AUTODRAW' + json.dumps( [log.logger.i, log.logger.heap.record(res)])) + '\n')) except (SchemeError, ZeroDivisionError, RecursionError, ValueError) as e: if isinstance(e, ParseError): log.logger.new_expr() raise if (not log.logger.fragile): log.logger.raw_out('Traceback (most recent call last)\n') for (j, expr) in enumerate( log.logger.eval_stack[:(MAX_TRACEBACK_LENGTH - 1)]): log.logger.raw_out( (((str(j).ljust(3) + ' ') + expr) + '\n')) truncated = (len(log.logger.eval_stack) - MAX_TRACEBACK_LENGTH) if (len(log.logger.eval_stack) > MAX_TRACEBACK_LENGTH): log.logger.raw_out(''.join([ '[', '{}'.format(truncated), ' lines omitted from traceback]\n' ])) log.logger.raw_out((((str( (len(log.logger.eval_stack) - 1)).ljust(3) + ' ') + log.logger.eval_stack[(-1)]) + '\n')) log.logger.out(e) except TimeLimitException: if (not log.logger.fragile): log.logger.out('Time limit exceeded.') log.logger.new_expr() if empty: log.logger.new_expr() holder = Holder(Undefined, None) Root.setroot(holder) evaluate(Undefined, global_frame, holder) log.logger.new_expr()