def test_changing_a_variable(): assert (do_eval_debug("d=3 d=d+4", 2) == [ [(None, { "d": NumberValue(3.0) })], [(None, { "d": NumberValue(7.0) })], ])
def test_multiplying_a_variable(): assert (do_eval_debug("2=d3.1d", 2) == [ [(None, { "d": NumberValue(2.0) })], [(None, { "d": NumberValue(6.2) })], ])
def _add_graft_symbols(env: Env): env.set("f", NumberValue(0)) # Fork ID env.set("x", NumberValue(0.0)) # x coord env.set("y", NumberValue(0.0)) # y coord env.set("d", NumberValue(0.0)) # direction in degrees env.set("s", NumberValue(10.0)) # step size env.set("r", NumberValue(0.0)) # red 0-100 (and 0 to -100) env.set("g", NumberValue(0.0)) # green 0-100 (and 0 to -100) env.set("b", NumberValue(0.0)) # blue 0-100 (and 0 to -100) env.set("a", NumberValue(100.0)) # alpha 0-100 (and 0 to -100) env.set("z", NumberValue(5.0)) # brush size env.set("D", NativeFunctionValue(functions.dot)) env.set("F", NativeFunctionValue(functions.fork)) env.set("J", NativeFunctionValue(functions.jump)) env.set("L", NativeFunctionValue(functions.line_to)) env.set("R", NativeFunctionValue(functions.random)) env.set("S", NativeFunctionValue(functions.step))
def get(self, name): if name in self._items: return self._items[name] elif self._parent is not None: return self._parent.get(name) else: self._items[name] = NumberValue(0.0) return self._items[name]
def _modify(self, modify_stmt: Modify): var_name = modify_stmt.sym val = self._value(modify_stmt.value) op = _operator_fn(modify_stmt.op) self.env.set( var_name, NumberValue(op(self.env.get(var_name).value, val.value)) ) return None
def round_value(v): if type(v) == float: return round_float(v) elif type(v) == int: return float(v) elif type(v) == NumberValue: return NumberValue(round_value(v.value)) elif type(v) == Pt: return round_pt(v) elif type(v) in (Line, Dot): return round_stroke(v) else: return v
def _eval(env, expr): typ = type(expr) if typ == NumberTree: return NumberValue(float(expr.value)) elif typ == NegativeTree: return NumberValue(-_eval(env, expr.value).value) elif typ == StringTree: return StringValue(expr.value) elif typ in (NoneValue, NativeFunctionValue): return expr elif typ == OperationTree: return _operation(expr, env) elif typ == LabelTree: raise Exception("You cannot (yet?) define labels inside functions.") elif typ == SymbolTree: ret = env.get(expr.value) if ret is None: raise Exception("Unknown symbol '%s'." % expr.value) else: return ret elif typ == AssignmentTree: var_name = expr.symbol.value val = _eval(env, expr.value) env.set(var_name, val) return val elif typ == ModifyTree: return _modify(expr, env) elif typ == FunctionCallTree: return _function_call(expr, env) elif typ == FunctionDefTree: return UserFunctionValue(expr.params, expr.body, env.make_child()) elif typ == ArrayTree: return ArrayValue([_eval(env, x) for x in expr.value]) elif typ in (ArrayValue, NativeFunctionValue, NoneValue, NumberValue, StringValue, UserFunctionValue): return expr else: raise Exception("Unknown expression type: " + str(expr))
def _value(self, value_expr): type_ = type(value_expr) if type_ == Number: neg = -1.0 if value_expr.negative else 1.0 return NumberValue(float(value_expr.value) * neg) elif type_ == FunctionCall: return self._function_call(value_expr) elif type_ == Symbol: return self.env.get(value_expr.value) else: raise Exception( "I don't know how to evaluate a value like %s." % str(value_expr) )
def _operation(expr, env): arg1 = _eval(env, expr.left) arg2 = _eval(env, expr.right) if expr.operation == "+": return NumberValue(arg1.value + arg2.value) elif expr.operation == "-": return NumberValue(arg1.value - arg2.value) elif expr.operation == "*": return NumberValue(arg1.value * arg2.value) elif expr.operation == "/": return NumberValue(arg1.value / arg2.value) elif expr.operation == ">": return NumberValue(1.0 if arg1.value > arg2.value else 0.0) elif expr.operation == "<": return NumberValue(1.0 if arg1.value < arg2.value else 0.0) elif expr.operation == ">=": return NumberValue(1.0 if arg1.value >= arg2.value else 0.0) elif expr.operation == "<=": return NumberValue(1.0 if arg1.value <= arg2.value else 0.0) elif expr.operation == "==": return NumberValue(1.0 if arg1.value == arg2.value else 0.0) else: raise Exception("Unknown operation: " + expr.operation)
def _modify(expr: ModifyTree, env): var_name = expr.symbol.value val = _eval(env, expr.value) if type(val) is list: # TODO strokes as a monad assert len(val) == 1 val = val[0] val = val.value prev_val = env.get(var_name).value if expr.operation == "+=": new_val = prev_val + val elif expr.operation == "-=": new_val = prev_val - val elif expr.operation == "*=": new_val = prev_val * val elif expr.operation == "/=": new_val = prev_val / val else: raise Exception("Unknown modify operation: " + expr.operation) env.set(var_name, NumberValue(new_val)) return env.get(var_name)
def test_subtracting_a_variable_removes_ten(): assert do_eval("-d", 1) == [] assert (do_eval_debug("-d", 1) == [[(None, {"d": NumberValue(-10.0)})]])
def test_incrementing_a_variable_adds_ten(): assert do_eval("+d", 100) == [] # Does terminate even though no strokes assert (do_eval_debug("+d", 1) == [[(None, {"d": NumberValue(10.0)})]])
def test_setting_a_variable(): assert (do_eval_debug("d=3", 1) == [[(None, {"d": NumberValue(3)})]])
def test_subtracting_from_a_variable(): assert do_eval("d-=10", 1) == [] assert (do_eval_debug("d-=10", 1) == [[(None, {"d": NumberValue(-10.0)})]])
def test_turn_right_and_jump(): assert (do_eval_debug("90+d25=s:J:S", 4) == [ [( None, { "d": NumberValue(90.0) }, )], [( None, { "d": NumberValue(90.0), "s": NumberValue(25.0) }, )], [( None, { "x": NumberValue(25.0), "d": NumberValue(90.0), "s": NumberValue(25.0), "xprev": NumberValue(0.0), "yprev": NumberValue(0.0) }, )], [( Line(Pt(25.0, 0.0), Pt(50.0, 0.0)), { "x": NumberValue(50.0), "d": NumberValue(90.0), "s": NumberValue(25.0), "xprev": NumberValue(25.0), "yprev": NumberValue(0.0), }, )], ])
def test_adding_a_negative_subtracts(): assert (do_eval_debug("-2+d", 1) == [[(None, {"d": NumberValue(-2.0)})]])
def impl(env, num): return NumberValue(fn(math.radians(num.value)))
def len_(env, array): return NumberValue(len(array.value))
def set_pos(self, pos: Pt): self.env.set("xprev", self.env.get("x")) self.env.set("yprev", self.env.get("y")) self.env.set("x", NumberValue(pos.x)) self.env.set("y", NumberValue(pos.y))
def random(env): return NumberValue(float(env.rand.__call__(-10, 10)))
def set_fork_id(self, new_id): self.env.set("f", NumberValue(new_id))
def TODO_FAILS_test_subtracting_a_negative(): assert (do_eval_debug("d-=-2", 1) == [[(None, {"d": NumberValue(2.0)})]])
def test_subtracting(): assert (do_eval_debug("2-d", 1) == [[(None, {"d": NumberValue(-2.0)})]]) assert (do_eval_debug("-2-d", 1) == [[(None, {"d": NumberValue(2.0)})]])
def test_dividing(): assert (do_eval_debug("2/s", 1) == [[(None, {"s": NumberValue(5.0)})]]) assert (do_eval_debug("-2/s", 1) == [[(None, {"s": NumberValue(-5.0)})]])
def impl(env, num): return NumberValue(math.degrees(fn(num.value)))
def impl(env, num1, num2): return NumberValue(math.degrees(fn(num1.value, num2.value)))
def impl(env, num1, num2): return NumberValue(fn(num1.value, num2.value))
def impl(env, num): return NumberValue(fn(num.value))
def TODO_FAILS_test_adding_a_negative_subtracts(): assert (do_eval_debug("d+=-2", 1) == [[(None, {"d": NumberValue(-2.0)})]])