From 0f1bd4745663cfbc4233c9f9e198d67cc8f101a6 Mon Sep 17 00:00:00 2001
From: LatvianModder <latvianmodder@gmail.com>
Date: Sat, 23 Mar 2024 15:48:51 +0200
Subject: [PATCH] Removed Context from every method, moved some of its methods
 to Scope, removed Remapper

---
 build.gradle                                  |   7 +-
 .../java/dev/latvian/apps/ichor/Callable.java |   6 +-
 .../apps/ichor/CallableTypeAdapter.java       |   9 +-
 .../java/dev/latvian/apps/ichor/Context.java  | 451 +-----------------
 .../latvian/apps/ichor/DebuggerCallback.java  |   6 +
 .../dev/latvian/apps/ichor/Evaluable.java     |  22 +-
 .../dev/latvian/apps/ichor/Interpretable.java |   6 +-
 .../java/dev/latvian/apps/ichor/Parser.java   |   8 +-
 .../java/dev/latvian/apps/ichor/Remapper.java |  16 -
 .../dev/latvian/apps/ichor/RootScope.java     |  82 +++-
 .../java/dev/latvian/apps/ichor/Scope.java    | 362 +++++++++++++-
 .../dev/latvian/apps/ichor/ScriptValue.java   |  25 +
 .../java/dev/latvian/apps/ichor/Special.java  |  14 +-
 .../dev/latvian/apps/ichor/TypeAdapter.java   |   6 +-
 .../latvian/apps/ichor/annotation/Hidden.java |   5 +-
 .../apps/ichor/ast/expression/AstAwait.java   |   5 +-
 .../apps/ichor/ast/expression/AstCall.java    |  33 +-
 .../ast/expression/AstClassFunction.java      |   5 +-
 .../ast/expression/AstClassPrototype.java     |   9 +-
 .../apps/ichor/ast/expression/AstDelete.java  |   5 +-
 .../ichor/ast/expression/AstFunction.java     |   5 +-
 .../apps/ichor/ast/expression/AstGetBase.java |   5 +-
 .../ast/expression/AstGetByEvaluable.java     |  43 +-
 .../ichor/ast/expression/AstGetByIndex.java   |  25 +-
 .../ichor/ast/expression/AstGetByName.java    |  27 +-
 .../ast/expression/AstGetByNameOptional.java  |   9 +-
 .../apps/ichor/ast/expression/AstGetFrom.java |   5 +-
 .../ast/expression/AstGetScopeMember.java     |   7 +-
 .../apps/ichor/ast/expression/AstList.java    |   7 +-
 .../apps/ichor/ast/expression/AstMap.java     |   7 +-
 .../ast/expression/AstObjectPrototype.java    |   9 +-
 .../apps/ichor/ast/expression/AstSet.java     |   7 +-
 .../ast/expression/AstTempExpression.java     |   3 +-
 .../ast/expression/AstTemplateLiteral.java    |  29 +-
 .../apps/ichor/ast/expression/AstTernary.java |   5 +-
 .../apps/ichor/ast/expression/AstType.java    |  18 +-
 .../apps/ichor/ast/expression/AstTypeOf.java  |   5 +-
 .../ichor/ast/expression/binary/AstAdd.java   |  15 +-
 .../ichor/ast/expression/binary/AstAnd.java   |   5 +-
 .../expression/binary/AstBinaryBoolean.java   |  19 +-
 .../ast/expression/binary/AstBitwiseAnd.java  |  17 +-
 .../ast/expression/binary/AstBitwiseOr.java   |  17 +-
 .../ichor/ast/expression/binary/AstDiv.java   |   9 +-
 .../ichor/ast/expression/binary/AstEq.java    |   5 +-
 .../ichor/ast/expression/binary/AstGt.java    |   5 +-
 .../ichor/ast/expression/binary/AstGte.java   |   5 +-
 .../ichor/ast/expression/binary/AstIn.java    |   3 +-
 .../ast/expression/binary/AstInstanceOf.java  |   3 +-
 .../ichor/ast/expression/binary/AstLsh.java   |  13 +-
 .../ichor/ast/expression/binary/AstLt.java    |   5 +-
 .../ichor/ast/expression/binary/AstLte.java   |   5 +-
 .../ichor/ast/expression/binary/AstMod.java   |   9 +-
 .../ichor/ast/expression/binary/AstMul.java   |   9 +-
 .../ichor/ast/expression/binary/AstNc.java    |   7 +-
 .../ichor/ast/expression/binary/AstNeq.java   |   5 +-
 .../ichor/ast/expression/binary/AstOr.java    |   5 +-
 .../ichor/ast/expression/binary/AstPow.java   |   9 +-
 .../ichor/ast/expression/binary/AstRsh.java   |  13 +-
 .../ichor/ast/expression/binary/AstSeq.java   |   5 +-
 .../ichor/ast/expression/binary/AstSneq.java  |   5 +-
 .../ichor/ast/expression/binary/AstSub.java   |   9 +-
 .../ichor/ast/expression/binary/AstUrsh.java  |  13 +-
 .../ichor/ast/expression/binary/AstXor.java   |  17 +-
 .../ast/expression/unary/AstAdditive1.java    |  11 +-
 .../ast/expression/unary/AstBitwiseNot.java   |  13 +-
 .../ichor/ast/expression/unary/AstNegate.java |  13 +-
 .../ichor/ast/expression/unary/AstNot.java    |  17 +-
 .../ast/expression/unary/AstPositive.java     |  13 +-
 .../apps/ichor/ast/statement/AstBlock.java    |   5 +-
 .../apps/ichor/ast/statement/AstBreak.java    |   3 +-
 .../apps/ichor/ast/statement/AstClass.java    |   3 +-
 .../apps/ichor/ast/statement/AstContinue.java |   3 +-
 .../apps/ichor/ast/statement/AstDebugger.java |   5 +-
 .../apps/ichor/ast/statement/AstDoWhile.java  |   7 +-
 .../ichor/ast/statement/AstEmptyBlock.java    |   3 +-
 .../apps/ichor/ast/statement/AstExport.java   |   3 +-
 .../ast/statement/AstExpressionStatement.java |   5 +-
 .../apps/ichor/ast/statement/AstFor.java      |   7 +-
 .../apps/ichor/ast/statement/AstForIn.java    |   7 +-
 .../apps/ichor/ast/statement/AstForOf.java    |  17 +-
 .../AstFunctionDeclareStatement.java          |   5 +-
 .../apps/ichor/ast/statement/AstIf.java       |   9 +-
 .../ast/statement/AstInterpretableGroup.java  |   5 +-
 .../statement/AstMultiDeclareStatement.java   |   5 +-
 .../apps/ichor/ast/statement/AstReturn.java   |   5 +-
 .../statement/AstSingleDeclareStatement.java  |   5 +-
 .../ast/statement/AstSuperStatement.java      |   3 +-
 .../apps/ichor/ast/statement/AstSwitch.java   |   9 +-
 .../ichor/ast/statement/AstThisStatement.java |   3 +-
 .../apps/ichor/ast/statement/AstThrow.java    |   5 +-
 .../apps/ichor/ast/statement/AstTry.java      |   9 +-
 .../apps/ichor/ast/statement/AstWhile.java    |   7 +-
 .../apps/ichor/ast/statement/AstYield.java    |   3 +-
 .../ast/statement/decl/AstDeclaration.java    |   3 +-
 .../ast/statement/decl/DestructuredArray.java |  11 +-
 .../statement/decl/DestructuredArrayName.java |   7 +-
 .../statement/decl/DestructuredObject.java    |  11 +-
 .../decl/DestructuredObjectName.java          |   7 +-
 .../ast/statement/decl/NameDeclaration.java   |   5 +-
 .../decl/NestedDestructuredPart.java          |   9 +-
 .../ichor/java/AnnotatedElementPrototype.java |  15 +-
 .../apps/ichor/java/BooleanPrototype.java     |  11 +-
 .../apps/ichor/java/JavaClassPrototype.java   |  15 +-
 .../latvian/apps/ichor/java/JavaMembers.java  |   5 +-
 .../apps/ichor/java/LocalJavaMembers.java     |  22 +-
 .../apps/ichor/java/StaticJavaMembers.java    |  22 +-
 .../apps/ichor/prototype/Prototype.java       | 124 +++--
 .../ichor/prototype/PrototypeConstant.java    |   3 +-
 .../ichor/prototype/PrototypeConstructor.java |   3 +-
 .../ichor/prototype/PrototypeFunction.java    |   9 +-
 .../ichor/prototype/PrototypeProperty.java    |   5 +-
 .../prototype/PrototypeStaticFunction.java    |   9 +-
 .../prototype/PrototypeStaticProperty.java    |   5 +-
 .../ichor/prototype/PrototypeSupplier.java    |   3 +-
 .../ichor/prototype/PrototypeTypeAdapter.java |   9 +-
 .../latvian/apps/ichor/token/TokenStream.java |  27 +-
 .../dev/latvian/apps/ichor/type/ArrayJS.java  |   9 +-
 .../latvian/apps/ichor/type/CollectionJS.java |  15 +-
 .../latvian/apps/ichor/type/IterableJS.java   |  21 +-
 .../dev/latvian/apps/ichor/type/ListJS.java   |  23 +-
 .../dev/latvian/apps/ichor/type/MapJS.java    |  25 +-
 .../dev/latvian/apps/ichor/type/MathJS.java   |   7 +-
 .../dev/latvian/apps/ichor/type/NumberJS.java |  69 ++-
 .../dev/latvian/apps/ichor/type/ObjectJS.java |  35 +-
 .../dev/latvian/apps/ichor/type/RegExpJS.java |  11 +-
 .../dev/latvian/apps/ichor/type/SetJS.java    |  29 +-
 .../dev/latvian/apps/ichor/type/StringJS.java |  49 +-
 .../ichor/util/ClassFunctionInstance.java     |  11 +-
 .../apps/ichor/util/ClassPrototype.java       |  13 +-
 .../apps/ichor/util/EvaluableConstant.java    |   3 +-
 .../apps/ichor/util/FunctionInstance.java     |  16 +-
 .../latvian/apps/ichor/util/Functions.java    |  33 +-
 .../latvian/apps/ichor/util/IchorUtils.java   |  82 ++--
 .../latvian/apps/ichor/util/JavaArray.java    |  13 +-
 .../apps/ichor/test/InterpreterTests.java     |  22 +-
 .../latvian/apps/ichor/test/ParserTests.java  |   4 +-
 .../latvian/apps/ichor/test/TokenTests.java   |   2 +-
 137 files changed, 1222 insertions(+), 1348 deletions(-)
 create mode 100644 src/main/java/dev/latvian/apps/ichor/DebuggerCallback.java
 delete mode 100644 src/main/java/dev/latvian/apps/ichor/Remapper.java
 create mode 100644 src/main/java/dev/latvian/apps/ichor/ScriptValue.java

diff --git a/build.gradle b/build.gradle
index 0974aec..4a4d41b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -19,9 +19,10 @@ repositories {
 
 dependencies {
 	compileOnly('org.jetbrains:annotations:23.0.0')
-	testImplementation('org.junit.jupiter:junit-jupiter-api:5.9.0')
-	testImplementation('org.junit.jupiter:junit-jupiter-engine:5.9.0')
-	testImplementation('junit:junit:4.13.2')
+	implementation("org.ow2.asm:asm:9.2")
+	testImplementation('org.junit.jupiter:junit-jupiter-api:5.10.2')
+	testImplementation('org.junit.jupiter:junit-jupiter-engine:5.10.2')
+	// testImplementation('junit:junit:4.13.2')
 }
 
 jar {
diff --git a/src/main/java/dev/latvian/apps/ichor/Callable.java b/src/main/java/dev/latvian/apps/ichor/Callable.java
index 89cb8a5..92c13a8 100644
--- a/src/main/java/dev/latvian/apps/ichor/Callable.java
+++ b/src/main/java/dev/latvian/apps/ichor/Callable.java
@@ -4,9 +4,9 @@
 
 @FunctionalInterface
 public interface Callable {
-	Object call(Context cx, Scope scope, Object[] args, boolean hasNew);
+	Object call(Scope scope, Object[] args, boolean hasNew);
 
-	default Object[] evalArgs(Context cx, Scope scope, Object[] arguments) {
+	default Object[] evalArgs(Scope scope, Object[] arguments) {
 		if (arguments.length == 0) {
 			return Empty.OBJECTS;
 		}
@@ -14,7 +14,7 @@ default Object[] evalArgs(Context cx, Scope scope, Object[] arguments) {
 		var args = arguments;
 
 		for (int i = 0; i < args.length; i++) {
-			var a = cx.eval(scope, args[i]);
+			var a = scope.eval(args[i]);
 
 			if (a != args[i]) {
 				if (args == arguments) {
diff --git a/src/main/java/dev/latvian/apps/ichor/CallableTypeAdapter.java b/src/main/java/dev/latvian/apps/ichor/CallableTypeAdapter.java
index 3518c61..a93ee6f 100644
--- a/src/main/java/dev/latvian/apps/ichor/CallableTypeAdapter.java
+++ b/src/main/java/dev/latvian/apps/ichor/CallableTypeAdapter.java
@@ -7,14 +7,12 @@
 import java.lang.reflect.Proxy;
 
 public interface CallableTypeAdapter extends Callable, TypeAdapter, InvocationHandler {
-	Context getEvalContext();
-
 	Scope getEvalScope();
 
 	@Override
 	@SuppressWarnings("unchecked")
-	default <T> T adapt(Context cx, Scope scope, Class<T> type) {
-		return (T) Proxy.newProxyInstance(cx.getClassLoader() == null ? type.getClassLoader() : cx.getClassLoader(), new Class[]{type}, this);
+	default <T> T adapt(Scope scope, Class<T> type) {
+		return (T) Proxy.newProxyInstance(scope.root.context.getClassLoader() == null ? type.getClassLoader() : scope.root.context.getClassLoader(), new Class[]{type}, this);
 	}
 
 	@Override
@@ -32,8 +30,7 @@ default Object invoke(Object proxy, Method method, Object[] args) throws Throwab
 			return InvocationHandler.invokeDefault(proxy, method, args);
 		}
 
-		var cx = getEvalContext();
 		var scope = getEvalScope();
-		return cx.as(scope, call(cx, scope, args == null ? Empty.OBJECTS : args, false), method.getReturnType());
+		return scope.as(call(scope, args == null ? Empty.OBJECTS : args, false), method.getReturnType());
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/Context.java b/src/main/java/dev/latvian/apps/ichor/Context.java
index af29c35..21eb500 100644
--- a/src/main/java/dev/latvian/apps/ichor/Context.java
+++ b/src/main/java/dev/latvian/apps/ichor/Context.java
@@ -1,122 +1,25 @@
 package dev.latvian.apps.ichor;
 
-import dev.latvian.apps.ichor.ast.AstStringBuilder;
-import dev.latvian.apps.ichor.error.CastError;
-import dev.latvian.apps.ichor.error.InternalScriptError;
-import dev.latvian.apps.ichor.java.AnnotatedElementPrototype;
-import dev.latvian.apps.ichor.java.BooleanPrototype;
-import dev.latvian.apps.ichor.java.JavaClassPrototype;
-import dev.latvian.apps.ichor.prototype.Prototype;
-import dev.latvian.apps.ichor.prototype.PrototypeSupplier;
-import dev.latvian.apps.ichor.type.ArrayJS;
-import dev.latvian.apps.ichor.type.CollectionJS;
-import dev.latvian.apps.ichor.type.IterableJS;
-import dev.latvian.apps.ichor.type.ListJS;
-import dev.latvian.apps.ichor.type.MapJS;
-import dev.latvian.apps.ichor.type.MathJS;
-import dev.latvian.apps.ichor.type.NumberJS;
-import dev.latvian.apps.ichor.type.ObjectJS;
-import dev.latvian.apps.ichor.type.RegExpJS;
-import dev.latvian.apps.ichor.type.SetJS;
-import dev.latvian.apps.ichor.type.StringJS;
-import dev.latvian.apps.ichor.util.IchorUtils;
-import dev.latvian.apps.ichor.util.JavaArray;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-import java.util.regex.Pattern;
 
 public class Context {
-	private final Map<Class<?>, Prototype<?>> classPrototypes;
 	private int maxScopeDepth;
 	private long interpretingTimeout;
 	private long tokenStreamTimeout;
-	private Remapper remapper;
 	private ClassLoader classLoader;
 	private Executor timeoutExecutor, timeoutExecutorAfter;
-	private Consumer<Scope> debuggerCallback;
-
-	public final Prototype<?> objectPrototype,
-			arrayPrototype,
-			classPrototype,
-			stringPrototype,
-			numberPrototype,
-			booleanPrototype,
-			jsObjectPrototype,
-			jsArrayPrototype,
-			jsMathPrototype,
-			jsMapPrototype,
-			jsSetPrototype,
-			regExpPrototype,
-			listPrototype,
-			collectionPrototype,
-			iterablePrototype;
-
-	public final List<Prototype<?>> safePrototypes;
+	private DebuggerCallback debuggerCallback;
 
 	public Context() {
-		classPrototypes = new IdentityHashMap<>();
 		maxScopeDepth = 1000;
 		interpretingTimeout = 30000L;
 		tokenStreamTimeout = 5000L;
-		remapper = null;
 		classLoader = null;
 		timeoutExecutor = null;
 		timeoutExecutorAfter = null;
-
-		objectPrototype = new Prototype<>(this, Object.class);
-		arrayPrototype = new Prototype<>(this, Object[].class);
-		classPrototype = new Prototype<>(this, Class.class);
-		stringPrototype = new StringJS(this);
-		numberPrototype = new NumberJS(this);
-		booleanPrototype = new BooleanPrototype(this);
-		jsObjectPrototype = new ObjectJS(this);
-		jsArrayPrototype = new ArrayJS(this);
-		jsMathPrototype = new MathJS(this);
-		jsMapPrototype = new MapJS(this);
-		jsSetPrototype = new SetJS(this);
-		regExpPrototype = new RegExpJS(this);
-		listPrototype = new ListJS(this);
-		collectionPrototype = new CollectionJS(this);
-		iterablePrototype = new IterableJS(this);
-
-		safePrototypes = new ArrayList<>();
-		safePrototypes.add(stringPrototype);
-		safePrototypes.add(numberPrototype);
-		safePrototypes.add(booleanPrototype);
-		safePrototypes.add(jsObjectPrototype);
-		safePrototypes.add(jsArrayPrototype);
-		safePrototypes.add(jsMathPrototype);
-		safePrototypes.add(jsMapPrototype);
-		safePrototypes.add(jsSetPrototype);
-		safePrototypes.add(regExpPrototype);
-
-		registerPrototype(new JavaClassPrototype(this));
-		registerPrototype(new AnnotatedElementPrototype(this));
-	}
-
-	public List<Prototype<?>> getSafePrototypes() {
-		return safePrototypes;
-	}
-
-	public void registerPrototype(Prototype<?> prototype) {
-		classPrototypes.put(prototype.type, prototype);
 	}
 
 	public int getMaxScopeDepth() {
@@ -143,15 +46,6 @@ public void setTokenStreamTimeout(long tokenStreamTimeout) {
 		this.tokenStreamTimeout = tokenStreamTimeout;
 	}
 
-	@Nullable
-	public Remapper getRemapper() {
-		return remapper;
-	}
-
-	public void setRemapper(Remapper r) {
-		remapper = r;
-	}
-
 	@Nullable
 	public ClassLoader getClassLoader() {
 		return classLoader;
@@ -183,357 +77,18 @@ public void setTimeoutExecutorAfter(Executor executor) {
 		timeoutExecutorAfter = executor;
 	}
 
-	public void setDebuggerCallback(Consumer<Scope> callback) {
+	public void setDebuggerCallback(DebuggerCallback callback) {
 		debuggerCallback = callback;
 	}
 
 	public void onDebugger(Scope scope) {
 		if (debuggerCallback != null) {
-			debuggerCallback.accept(scope);
-		}
-	}
-
-	public Object eval(Scope scope, Object o) {
-		if (o == Special.UNDEFINED || o instanceof Callable) {
-			return o;
-		} else if (o instanceof Evaluable eval) {
-			return eval.eval(this, scope);
-		} else {
-			return o;
+			debuggerCallback.onDebugger(scope);
 		}
 	}
 
-	public void asString(Scope scope, Object o, StringBuilder builder, boolean escape) {
-		if (o == null) {
-			builder.append("null");
-		} else if (o instanceof Number) {
-			AstStringBuilder.wrapNumber(o, builder);
-		} else if (o instanceof Character || o instanceof CharSequence) {
-			if (escape) {
-				AstStringBuilder.wrapString(o, builder);
-			} else {
-				builder.append(o);
-			}
-		} else if (o instanceof Boolean || o instanceof Special) {
-			builder.append(o);
-		} else if (o instanceof Evaluable eval) {
-			eval.evalString(this, scope, builder);
-		} else {
-			var p = getPrototype(scope, o);
-
-			if (o == p || !p.asString(this, scope, p.cast(o), builder, escape)) {
-				builder.append(o);
-			}
-		}
-	}
-
-	public String asString(Scope scope, Object o, boolean escape) {
-		if (o == null) {
-			return "null";
-		} else if (o instanceof Number) {
-			return AstStringBuilder.wrapNumber(o);
-		} else if (o instanceof Character || o instanceof CharSequence) {
-			if (escape) {
-				var builder = new StringBuilder();
-				AstStringBuilder.wrapString(o, builder);
-				return builder.toString();
-			} else {
-				return o.toString();
-			}
-		} else if (o instanceof Boolean || o instanceof Special) {
-			return o.toString();
-		} else if (o instanceof Evaluable eval) {
-			var builder = new StringBuilder();
-			eval.evalString(this, scope, builder);
-			return builder.toString();
-		} else {
-			var p = getPrototype(scope, o);
-
-			if (o == p) {
-				return o.toString();
-			}
-
-			var builder = new StringBuilder();
-
-			if (!p.asString(this, scope, p.cast(o), builder, escape)) {
-				return o.toString();
-			}
-
-			return builder.toString();
-		}
-	}
-
-	private Number asNumber0(Scope scope, Object o) {
-		var p = getPrototype(scope, o);
-		var n = o == p ? null : p.asNumber(this, scope, p.cast(o));
-		return n == null ? IchorUtils.ONE : n;
-	}
-
-	public Number asNumber(Scope scope, Object o) {
-		if (Special.isInvalid(o)) {
-			return IchorUtils.NaN;
-		} else if (o instanceof Number) {
-			return (Number) o;
-		} else if (o instanceof Boolean) {
-			return (Boolean) o ? IchorUtils.ONE : IchorUtils.ZERO;
-		} else if (o instanceof CharSequence) {
-			try {
-				return IchorUtils.parseNumber(o.toString());
-			} catch (Exception ex) {
-				return IchorUtils.NaN;
-			}
-		} else if (o instanceof Evaluable) {
-			return ((Evaluable) o).evalDouble(this, scope);
-		}
-
-		return asNumber0(scope, o);
-	}
-
-	public double asDouble(Scope scope, Object o) {
-		if (Special.isInvalid(o)) {
-			return Double.NaN;
-		} else if (o instanceof Number) {
-			return ((Number) o).doubleValue();
-		} else if (o instanceof Boolean) {
-			return (Boolean) o ? 1D : 0D;
-		} else if (o instanceof CharSequence) {
-			try {
-				return IchorUtils.parseNumber(o.toString()).doubleValue();
-			} catch (Exception ex) {
-				return Double.NaN;
-			}
-		} else if (o instanceof Evaluable) {
-			return ((Evaluable) o).evalDouble(this, scope);
-		}
-
-		return asNumber0(scope, o).doubleValue();
-	}
-
-	public int asInt(Scope scope, Object o) {
-		if (Special.isInvalid(o)) {
-			return 0;
-		} else if (o instanceof Number) {
-			return ((Number) o).intValue();
-		} else if (o instanceof Boolean) {
-			return (Boolean) o ? 1 : 0;
-		} else if (o instanceof CharSequence) {
-			try {
-				return IchorUtils.parseNumber(o.toString()).intValue();
-			} catch (Exception ex) {
-				throw new InternalScriptError(ex);
-			}
-		} else if (o instanceof Evaluable) {
-			return ((Evaluable) o).evalInt(this, scope);
-		}
-
-		return asNumber0(scope, o).intValue();
-	}
-
-	public long asLong(Scope scope, Object o) {
-		if (Special.isInvalid(o)) {
-			return 0L;
-		} else if (o instanceof Number) {
-			return ((Number) o).longValue();
-		} else if (o instanceof Boolean) {
-			return (Boolean) o ? 1L : 0L;
-		} else if (o instanceof CharSequence) {
-			try {
-				return IchorUtils.parseNumber(o.toString()).longValue();
-			} catch (Exception ex) {
-				throw new InternalScriptError(ex);
-			}
-		} else if (o instanceof Evaluable) {
-			// add evalLong
-			return ((Evaluable) o).evalInt(this, scope);
-		}
-
-		return asNumber0(scope, o).longValue();
-	}
-
-	public boolean asBoolean(Scope scope, Object o) {
-		if (o instanceof Boolean) {
-			return (Boolean) o;
-		} else if (Special.isInvalid(o)) {
-			return false;
-		} else if (o instanceof Number) {
-			return ((Number) o).doubleValue() != 0D;
-		} else if (o instanceof CharSequence) {
-			return !o.toString().isEmpty();
-		} else if (o instanceof Evaluable) {
-			return ((Evaluable) o).evalBoolean(this, scope);
-		}
-
-		var p = getPrototype(scope, o);
-		var n = o == p ? null : p.asBoolean(this, scope, p.cast(o));
-		return n == null ? Boolean.TRUE : n;
-	}
-
-	public char asChar(Scope scope, Object o) {
-		if (o instanceof Character) {
-			return (Character) o;
-		} else if (o instanceof CharSequence) {
-			return ((CharSequence) o).charAt(0);
-		} else if (o instanceof Number) {
-			return (char) ((Number) o).intValue();
-		} else if (o instanceof Evaluable) {
-			var builder = new StringBuilder();
-			((Evaluable) o).evalString(this, scope, builder);
-			return builder.charAt(0);
-		}
-
-		throw new CastError(o, "Character");
-	}
-
-	@SuppressWarnings("rawtypes")
-	public Class asClass(Scope scope, Object o) {
-		return o instanceof Class s ? s : (Class) as(scope, o, Class.class);
-	}
-
-	@SuppressWarnings("rawtypes")
-	public Map asMap(Scope scope, Object o) {
-		return o instanceof Map s ? s : (Map) as(scope, o, Map.class);
-	}
-
-	@SuppressWarnings("rawtypes")
-	public List asList(Scope scope, Object o) {
-		return o instanceof List s ? s : o != null ? o.getClass().isArray() ? JavaArray.of(o) : (List) as(scope, o, List.class) : null;
-	}
-
-	public Object as(Scope scope, Object o, @Nullable Class<?> toType) {
-		if (Special.isInvalid(o)) {
-			return null;
-		} else if (toType == null || toType == Void.TYPE || toType == Object.class || toType.isInstance(o)) {
-			return o;
-		} else if (toType == String.class || toType == CharSequence.class) {
-			return asString(scope, o, false);
-		} else if (toType == Number.class) {
-			return asNumber(scope, o);
-		} else if (toType == Boolean.class || toType == Boolean.TYPE) {
-			return asBoolean(scope, o);
-		} else if (toType == Character.class || toType == Character.TYPE) {
-			return asChar(scope, o);
-		} else if (toType == Byte.class || toType == Byte.TYPE) {
-			return asNumber(scope, o).byteValue();
-		} else if (toType == Short.class || toType == Short.TYPE) {
-			return asNumber(scope, o).shortValue();
-		} else if (toType == Integer.class || toType == Integer.TYPE) {
-			return asInt(scope, o);
-		} else if (toType == Long.class || toType == Long.TYPE) {
-			return asLong(scope, o);
-		} else if (toType == Float.class || toType == Float.TYPE) {
-			return asNumber(scope, o).floatValue();
-		} else if (toType == Double.class || toType == Double.TYPE) {
-			return asDouble(scope, o);
-		} else if (o instanceof TypeAdapter typeAdapter && typeAdapter.canAdapt(this, toType)) {
-			return typeAdapter.adapt(this, scope, toType);
-		}
-
-		var c = customAs(scope, o, toType);
-
-		if (c != Special.NOT_FOUND) {
-			return c;
-		}
-
-		var p = getPrototype(scope, o);
-		var a = p.adapt(this, scope, p.cast(o), toType);
-
-		if (a != Special.NOT_FOUND) {
-			return a;
-		} else if (o instanceof Iterable<?> itr && toType.isArray()) {
-			return JavaArray.adaptToArray(this, scope, itr, toType);
-		} else {
-			throw new CastError(o, toType.getName());
-		}
-	}
-
-	@Nullable
-	protected Object customAs(Scope scope, Object o, Class<?> toType) {
-		return Special.NOT_FOUND;
-	}
-
-	public Prototype<?> getPrototype(Scope scope, Object o) {
-		if (o == null) {
-			return Special.NULL.prototype;
-		} else if (o instanceof PrototypeSupplier s) {
-			return s.getPrototype(this, scope);
-		} else if (o instanceof Boolean) {
-			return booleanPrototype;
-		} else if (o instanceof Number) {
-			return numberPrototype;
-		} else if (o instanceof CharSequence) {
-			return stringPrototype;
-		} else if (o instanceof Class) {
-			return classPrototype;
-		} else if (o instanceof Pattern) {
-			return regExpPrototype;
-		} else if (o.getClass().isArray()) {
-			return arrayPrototype;
-		}
-
-		return getClassPrototype(o.getClass());
-	}
-
-	public Prototype<?> getClassPrototype(Class<?> c) {
-		if (c == Boolean.class) {
-			return booleanPrototype;
-		} else if (c == Number.class) {
-			return numberPrototype;
-		} else if (c == String.class) {
-			return stringPrototype;
-		} else if (c == Class.class) {
-			return classPrototype;
-		} else if (c == Map.class || c == HashMap.class || c == LinkedHashMap.class || c == IdentityHashMap.class || c == EnumMap.class) {
-			return jsMapPrototype;
-		} else if (c == Set.class || c == HashSet.class || c == LinkedHashSet.class || c == EnumSet.class) {
-			return jsSetPrototype;
-		} else if (c == List.class || c == ArrayList.class || c == LinkedList.class) {
-			return listPrototype;
-		} else if (c == Collection.class) {
-			return collectionPrototype;
-		} else if (c == Iterable.class) {
-			return iterablePrototype;
-		} else if (c == Pattern.class) {
-			return regExpPrototype;
-		} else if (c.isArray()) {
-			return arrayPrototype;
-		}
-
-		var p = classPrototypes.get(c);
-
-		if (p == null) {
-			p = new Prototype<>(this, c);
-			classPrototypes.put(c, p);
-		}
-
-		return p;
-	}
-
 	@Override
 	public String toString() {
 		return "Context";
 	}
-
-	public boolean equals(Scope scope, Object left, Object right, boolean shallow) {
-		if (left == right) {
-			return true;
-		} else if (left instanceof Number l && right instanceof Number r) {
-			return Math.abs(l.doubleValue() - r.doubleValue()) < 0.00001D;
-		} else if (left instanceof CharSequence || left instanceof Character || right instanceof CharSequence || right instanceof Character) {
-			return asString(scope, left, false).equals(asString(scope, right, false));
-		} else {
-			var p = getPrototype(scope, left);
-			return p.equals(this, scope, p.cast(left), right, shallow);
-		}
-	}
-
-	public int compareTo(Scope scope, Object left, Object right) {
-		if (left == right || Objects.equals(left, right)) {
-			return 0;
-		} else if (left instanceof Number l && right instanceof Number r) {
-			return Math.abs(l.doubleValue() - r.doubleValue()) < 0.00001D ? 0 : Double.compare(l.doubleValue(), r.doubleValue());
-		} else {
-			var p = getPrototype(scope, right);
-			return p.compareTo(this, scope, p.cast(left), right);
-		}
-	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/DebuggerCallback.java b/src/main/java/dev/latvian/apps/ichor/DebuggerCallback.java
new file mode 100644
index 0000000..84e9ecb
--- /dev/null
+++ b/src/main/java/dev/latvian/apps/ichor/DebuggerCallback.java
@@ -0,0 +1,6 @@
+package dev.latvian.apps.ichor;
+
+@FunctionalInterface
+public interface DebuggerCallback {
+	void onDebugger(Scope scope);
+}
diff --git a/src/main/java/dev/latvian/apps/ichor/Evaluable.java b/src/main/java/dev/latvian/apps/ichor/Evaluable.java
index 2c521ca..708d8a2 100644
--- a/src/main/java/dev/latvian/apps/ichor/Evaluable.java
+++ b/src/main/java/dev/latvian/apps/ichor/Evaluable.java
@@ -1,35 +1,35 @@
 package dev.latvian.apps.ichor;
 
 public interface Evaluable {
-	Object eval(Context cx, Scope scope);
+	Object eval(Scope scope);
 
-	default void evalString(Context cx, Scope scope, StringBuilder builder) {
-		var e = this.eval(cx, scope);
+	default void evalString(Scope scope, StringBuilder builder) {
+		var e = this.eval(scope);
 
 		if (e == this) {
 			builder.append(this);
 		} else {
-			cx.asString(scope, e, builder, false);
+			scope.asString(e, builder, false);
 		}
 	}
 
-	default double evalDouble(Context cx, Scope scope) {
-		var e = this.eval(cx, scope);
+	default double evalDouble(Scope scope) {
+		var e = this.eval(scope);
 
 		if (e == this) {
 			return Double.NaN;
 		} else {
-			return cx.asDouble(scope, e);
+			return scope.asDouble(e);
 		}
 	}
 
-	default int evalInt(Context cx, Scope scope) {
-		var d = evalDouble(cx, scope);
+	default int evalInt(Scope scope) {
+		var d = evalDouble(scope);
 		return Double.isNaN(d) ? 0 : (int) d;
 	}
 
-	default boolean evalBoolean(Context cx, Scope scope) {
-		var d = evalDouble(cx, scope);
+	default boolean evalBoolean(Scope scope) {
+		var d = evalDouble(scope);
 		return !Double.isNaN(d) && d != 0D;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/Interpretable.java b/src/main/java/dev/latvian/apps/ichor/Interpretable.java
index 48a6e74..3da08f3 100644
--- a/src/main/java/dev/latvian/apps/ichor/Interpretable.java
+++ b/src/main/java/dev/latvian/apps/ichor/Interpretable.java
@@ -9,11 +9,11 @@
 public interface Interpretable {
 	Interpretable[] EMPTY_INTERPRETABLE_ARRAY = new Interpretable[0];
 
-	void interpret(Context cx, Scope scope);
+	void interpret(Scope scope);
 
-	default void interpretSafe(Context cx, Scope scope) {
+	default void interpretSafe(Scope scope) {
 		try {
-			interpret(cx, scope);
+			interpret(scope);
 		} catch (ScopeExit pass) {
 			throw pass;
 		} catch (IchorError pass) {
diff --git a/src/main/java/dev/latvian/apps/ichor/Parser.java b/src/main/java/dev/latvian/apps/ichor/Parser.java
index bad1eee..3b3f33c 100644
--- a/src/main/java/dev/latvian/apps/ichor/Parser.java
+++ b/src/main/java/dev/latvian/apps/ichor/Parser.java
@@ -110,24 +110,18 @@ private record BinaryOp(Function<Parser, Object> next, Token... tokens) {
 			Keyword.IN
 	};
 
-	private final Context context;
 	private final RootScope rootScope;
 	private PositionedToken current;
 	private final Stack<LabeledStatement> labeledStatements;
 	private final Map<String, AstType.Generic> genericTypeCache;
 
-	public Parser(Context cx, RootScope scope, PositionedToken r) {
-		context = cx;
+	public Parser(RootScope scope, PositionedToken r) {
 		rootScope = scope;
 		current = r;
 		labeledStatements = new Stack<>();
 		genericTypeCache = new HashMap<>();
 	}
 
-	public Context getContext() {
-		return context;
-	}
-
 	public RootScope getRootScope() {
 		return rootScope;
 	}
diff --git a/src/main/java/dev/latvian/apps/ichor/Remapper.java b/src/main/java/dev/latvian/apps/ichor/Remapper.java
deleted file mode 100644
index 32d3de2..0000000
--- a/src/main/java/dev/latvian/apps/ichor/Remapper.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package dev.latvian.apps.ichor;
-
-import dev.latvian.apps.ichor.util.Signature;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-public interface Remapper {
-	default String getFieldName(Context cx, Field field) {
-		return field.getName();
-	}
-
-	default String getMethodName(Context cx, Method method, Signature signature) {
-		return method.getName();
-	}
-}
diff --git a/src/main/java/dev/latvian/apps/ichor/RootScope.java b/src/main/java/dev/latvian/apps/ichor/RootScope.java
index c65a8ee..cada02d 100644
--- a/src/main/java/dev/latvian/apps/ichor/RootScope.java
+++ b/src/main/java/dev/latvian/apps/ichor/RootScope.java
@@ -1,14 +1,53 @@
 package dev.latvian.apps.ichor;
 
 import dev.latvian.apps.ichor.error.ScriptTimedOutError;
+import dev.latvian.apps.ichor.java.AnnotatedElementPrototype;
+import dev.latvian.apps.ichor.java.BooleanPrototype;
+import dev.latvian.apps.ichor.java.JavaClassPrototype;
+import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.slot.Slot;
+import dev.latvian.apps.ichor.type.ArrayJS;
+import dev.latvian.apps.ichor.type.CollectionJS;
+import dev.latvian.apps.ichor.type.IterableJS;
+import dev.latvian.apps.ichor.type.ListJS;
+import dev.latvian.apps.ichor.type.MapJS;
+import dev.latvian.apps.ichor.type.MathJS;
+import dev.latvian.apps.ichor.type.NumberJS;
+import dev.latvian.apps.ichor.type.ObjectJS;
+import dev.latvian.apps.ichor.type.RegExpJS;
+import dev.latvian.apps.ichor.type.SetJS;
+import dev.latvian.apps.ichor.type.StringJS;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
 public class RootScope extends Scope {
 	public final Context context;
 	public int maxScopeDepth;
 	public long interpretingTimeout;
 	protected long timeoutAt;
+	final Map<Class<?>, Prototype<?>> classPrototypes;
+
+	public final Prototype<?> objectPrototype,
+			arrayPrototype,
+			classPrototype,
+			stringPrototype,
+			numberPrototype,
+			booleanPrototype,
+			jsObjectPrototype,
+			jsArrayPrototype,
+			jsMathPrototype,
+			jsMapPrototype,
+			jsSetPrototype,
+			regExpPrototype,
+			listPrototype,
+			collectionPrototype,
+			iterablePrototype;
+
+	public final List<Prototype<?>> safePrototypes;
 
 	public RootScope(Context cx) {
 		super(null);
@@ -17,6 +56,45 @@ public RootScope(Context cx) {
 		scopeOwner = cx;
 		maxScopeDepth = cx.getMaxScopeDepth();
 		interpretingTimeout = cx.getInterpretingTimeout();
+		classPrototypes = new IdentityHashMap<>();
+
+		objectPrototype = new Prototype<>(this, Object.class);
+		arrayPrototype = new Prototype<>(this, Object[].class);
+		classPrototype = new Prototype<>(this, Class.class);
+		stringPrototype = new StringJS(this);
+		numberPrototype = new NumberJS(this);
+		booleanPrototype = new BooleanPrototype(this);
+		jsObjectPrototype = new ObjectJS(this);
+		jsArrayPrototype = new ArrayJS(this);
+		jsMathPrototype = new MathJS(this);
+		jsMapPrototype = new MapJS(this);
+		jsSetPrototype = new SetJS(this);
+		regExpPrototype = new RegExpJS(this);
+		listPrototype = new ListJS(this);
+		collectionPrototype = new CollectionJS(this);
+		iterablePrototype = new IterableJS(this);
+
+		safePrototypes = new ArrayList<>();
+		safePrototypes.add(stringPrototype);
+		safePrototypes.add(numberPrototype);
+		safePrototypes.add(booleanPrototype);
+		safePrototypes.add(jsObjectPrototype);
+		safePrototypes.add(jsArrayPrototype);
+		safePrototypes.add(jsMathPrototype);
+		safePrototypes.add(jsMapPrototype);
+		safePrototypes.add(jsSetPrototype);
+		safePrototypes.add(regExpPrototype);
+
+		registerPrototype(new JavaClassPrototype(this));
+		registerPrototype(new AnnotatedElementPrototype(this));
+	}
+
+	public List<Prototype<?>> getSafePrototypes() {
+		return safePrototypes;
+	}
+
+	public void registerPrototype(Prototype<?> prototype) {
+		classPrototypes.put(prototype.type, prototype);
 	}
 
 	public void addRoot(String name, @Nullable Object value) {
@@ -24,7 +102,7 @@ public void addRoot(String name, @Nullable Object value) {
 	}
 
 	public void addSafePrototypes() {
-		for (var p : context.getSafePrototypes()) {
+		for (var p : getSafePrototypes()) {
 			addRoot(p.getPrototypeName(), p);
 		}
 	}
@@ -44,7 +122,7 @@ public void interpret(Interpretable interpretable) {
 		timeoutAt = interpretingTimeout > 0L ? System.currentTimeMillis() + interpretingTimeout : 0L;
 
 		try {
-			interpretable.interpret(context, this);
+			interpretable.interpret(this);
 		} finally {
 			timeoutAt = 0L;
 		}
diff --git a/src/main/java/dev/latvian/apps/ichor/Scope.java b/src/main/java/dev/latvian/apps/ichor/Scope.java
index 988d627..6d80db1 100644
--- a/src/main/java/dev/latvian/apps/ichor/Scope.java
+++ b/src/main/java/dev/latvian/apps/ichor/Scope.java
@@ -1,18 +1,39 @@
 package dev.latvian.apps.ichor;
 
+import dev.latvian.apps.ichor.ast.AstStringBuilder;
+import dev.latvian.apps.ichor.error.CastError;
 import dev.latvian.apps.ichor.error.ConstantReassignError;
+import dev.latvian.apps.ichor.error.InternalScriptError;
 import dev.latvian.apps.ichor.error.RedeclarationError;
 import dev.latvian.apps.ichor.error.ScopeDepthError;
 import dev.latvian.apps.ichor.error.ScopeMemberNotFoundError;
+import dev.latvian.apps.ichor.prototype.Prototype;
+import dev.latvian.apps.ichor.prototype.PrototypeSupplier;
 import dev.latvian.apps.ichor.slot.EmptySlotMap;
 import dev.latvian.apps.ichor.slot.Slot;
 import dev.latvian.apps.ichor.slot.SlotMap;
 import dev.latvian.apps.ichor.util.AssignType;
 import dev.latvian.apps.ichor.util.ClassPrototype;
+import dev.latvian.apps.ichor.util.IchorUtils;
+import dev.latvian.apps.ichor.util.JavaArray;
 import dev.latvian.apps.ichor.util.ScopeWrapper;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 public class Scope {
 	public final Scope parent;
@@ -80,7 +101,7 @@ public void addImmutable(String name, @Nullable Object value) {
 	}
 
 	public void add(String name, Class<?> type) {
-		addImmutable(name, root.context.getClassPrototype(type));
+		addImmutable(name, getClassPrototype(type));
 	}
 
 	public void setScopeThis(Scope o) {
@@ -210,4 +231,343 @@ public String toString() {
 	public int getDepth() {
 		return depth;
 	}
+
+	public Object eval(Object o) {
+		if (o == Special.UNDEFINED || o instanceof Callable) {
+			return o;
+		} else if (o instanceof Evaluable eval) {
+			return eval.eval(this);
+		} else {
+			return o;
+		}
+	}
+
+	public void asString(Object o, StringBuilder builder, boolean escape) {
+		if (o == null) {
+			builder.append("null");
+		} else if (o instanceof Number) {
+			AstStringBuilder.wrapNumber(o, builder);
+		} else if (o instanceof Character || o instanceof CharSequence) {
+			if (escape) {
+				AstStringBuilder.wrapString(o, builder);
+			} else {
+				builder.append(o);
+			}
+		} else if (o instanceof Boolean || o instanceof Special) {
+			builder.append(o);
+		} else if (o instanceof Evaluable eval) {
+			eval.evalString(this, builder);
+		} else {
+			var p = getPrototype(o);
+
+			if (o == p || !p.asString(this, p.cast(o), builder, escape)) {
+				builder.append(o);
+			}
+		}
+	}
+
+	public String asString(Object o, boolean escape) {
+		if (o == null) {
+			return "null";
+		} else if (o instanceof Number) {
+			return AstStringBuilder.wrapNumber(o);
+		} else if (o instanceof Character || o instanceof CharSequence) {
+			if (escape) {
+				var builder = new StringBuilder();
+				AstStringBuilder.wrapString(o, builder);
+				return builder.toString();
+			} else {
+				return o.toString();
+			}
+		} else if (o instanceof Boolean || o instanceof Special) {
+			return o.toString();
+		} else if (o instanceof Evaluable eval) {
+			var builder = new StringBuilder();
+			eval.evalString(this, builder);
+			return builder.toString();
+		} else {
+			var p = getPrototype(o);
+
+			if (o == p) {
+				return o.toString();
+			}
+
+			var builder = new StringBuilder();
+
+			if (!p.asString(this, p.cast(o), builder, escape)) {
+				return o.toString();
+			}
+
+			return builder.toString();
+		}
+	}
+
+	private Number asNumber0(Object o) {
+		var p = getPrototype(o);
+		var n = o == p ? null : p.asNumber(this, p.cast(o));
+		return n == null ? IchorUtils.ONE : n;
+	}
+
+	public Number asNumber(Object o) {
+		if (Special.isInvalid(o)) {
+			return IchorUtils.NaN;
+		} else if (o instanceof Number) {
+			return (Number) o;
+		} else if (o instanceof Boolean) {
+			return (Boolean) o ? IchorUtils.ONE : IchorUtils.ZERO;
+		} else if (o instanceof CharSequence) {
+			try {
+				return IchorUtils.parseNumber(o.toString());
+			} catch (Exception ex) {
+				return IchorUtils.NaN;
+			}
+		} else if (o instanceof Evaluable) {
+			return ((Evaluable) o).evalDouble(this);
+		}
+
+		return asNumber0(o);
+	}
+
+	public double asDouble(Object o) {
+		if (Special.isInvalid(o)) {
+			return Double.NaN;
+		} else if (o instanceof Number) {
+			return ((Number) o).doubleValue();
+		} else if (o instanceof Boolean) {
+			return (Boolean) o ? 1D : 0D;
+		} else if (o instanceof CharSequence) {
+			try {
+				return IchorUtils.parseNumber(o.toString()).doubleValue();
+			} catch (Exception ex) {
+				return Double.NaN;
+			}
+		} else if (o instanceof Evaluable) {
+			return ((Evaluable) o).evalDouble(this);
+		}
+
+		return asNumber0(o).doubleValue();
+	}
+
+	public int asInt(Object o) {
+		if (Special.isInvalid(o)) {
+			return 0;
+		} else if (o instanceof Number) {
+			return ((Number) o).intValue();
+		} else if (o instanceof Boolean) {
+			return (Boolean) o ? 1 : 0;
+		} else if (o instanceof CharSequence) {
+			try {
+				return IchorUtils.parseNumber(o.toString()).intValue();
+			} catch (Exception ex) {
+				throw new InternalScriptError(ex);
+			}
+		} else if (o instanceof Evaluable) {
+			return ((Evaluable) o).evalInt(this);
+		}
+
+		return asNumber0(o).intValue();
+	}
+
+	public long asLong(Object o) {
+		if (Special.isInvalid(o)) {
+			return 0L;
+		} else if (o instanceof Number) {
+			return ((Number) o).longValue();
+		} else if (o instanceof Boolean) {
+			return (Boolean) o ? 1L : 0L;
+		} else if (o instanceof CharSequence) {
+			try {
+				return IchorUtils.parseNumber(o.toString()).longValue();
+			} catch (Exception ex) {
+				throw new InternalScriptError(ex);
+			}
+		} else if (o instanceof Evaluable) {
+			// add evalLong
+			return ((Evaluable) o).evalInt(this);
+		}
+
+		return asNumber0(o).longValue();
+	}
+
+	public boolean asBoolean(Object o) {
+		if (o instanceof Boolean) {
+			return (Boolean) o;
+		} else if (Special.isInvalid(o)) {
+			return false;
+		} else if (o instanceof Number) {
+			return ((Number) o).doubleValue() != 0D;
+		} else if (o instanceof CharSequence) {
+			return !o.toString().isEmpty();
+		} else if (o instanceof Evaluable) {
+			return ((Evaluable) o).evalBoolean(this);
+		}
+
+		var p = getPrototype(o);
+		var n = o == p ? null : p.asBoolean(this, p.cast(o));
+		return n == null ? Boolean.TRUE : n;
+	}
+
+	public char asChar(Object o) {
+		if (o instanceof Character) {
+			return (Character) o;
+		} else if (o instanceof CharSequence) {
+			return ((CharSequence) o).charAt(0);
+		} else if (o instanceof Number) {
+			return (char) ((Number) o).intValue();
+		} else if (o instanceof Evaluable) {
+			var builder = new StringBuilder();
+			((Evaluable) o).evalString(this, builder);
+			return builder.charAt(0);
+		}
+
+		throw new CastError(o, "Character");
+	}
+
+	@SuppressWarnings("rawtypes")
+	public Class asClass(Object o) {
+		return o instanceof Class s ? s : (Class) as(o, Class.class);
+	}
+
+	@SuppressWarnings("rawtypes")
+	public Map asMap(Object o) {
+		return o instanceof Map s ? s : (Map) as(o, Map.class);
+	}
+
+	@SuppressWarnings("rawtypes")
+	public List asList(Object o) {
+		return o instanceof List s ? s : o != null ? o.getClass().isArray() ? JavaArray.of(o) : (List) as(o, List.class) : null;
+	}
+
+	public Object as(Object o, @Nullable Class<?> toType) {
+		if (Special.isInvalid(o)) {
+			return null;
+		} else if (toType == null || toType == Void.TYPE || toType == Object.class || toType.isInstance(o)) {
+			return o;
+		} else if (toType == String.class || toType == CharSequence.class) {
+			return asString(o, false);
+		} else if (toType == Number.class) {
+			return asNumber(o);
+		} else if (toType == Boolean.class || toType == Boolean.TYPE) {
+			return asBoolean(o);
+		} else if (toType == Character.class || toType == Character.TYPE) {
+			return asChar(o);
+		} else if (toType == Byte.class || toType == Byte.TYPE) {
+			return asNumber(o).byteValue();
+		} else if (toType == Short.class || toType == Short.TYPE) {
+			return asNumber(o).shortValue();
+		} else if (toType == Integer.class || toType == Integer.TYPE) {
+			return asInt(o);
+		} else if (toType == Long.class || toType == Long.TYPE) {
+			return asLong(o);
+		} else if (toType == Float.class || toType == Float.TYPE) {
+			return asNumber(o).floatValue();
+		} else if (toType == Double.class || toType == Double.TYPE) {
+			return asDouble(o);
+		} else if (o instanceof TypeAdapter typeAdapter && typeAdapter.canAdapt(this, toType)) {
+			return typeAdapter.adapt(this, toType);
+		}
+
+		var c = customAs(o, toType);
+
+		if (c != Special.NOT_FOUND) {
+			return c;
+		}
+
+		var p = getPrototype(o);
+		var a = p.adapt(this, p.cast(o), toType);
+
+		if (a != Special.NOT_FOUND) {
+			return a;
+		} else if (o instanceof Iterable<?> itr && toType.isArray()) {
+			return JavaArray.adaptToArray(this, itr, toType);
+		} else {
+			throw new CastError(o, toType.getName());
+		}
+	}
+
+	@Nullable
+	protected Object customAs(Object o, Class<?> toType) {
+		return Special.NOT_FOUND;
+	}
+
+	public Prototype<?> getPrototype(Object o) {
+		if (o == null) {
+			return Special.NULL.prototype;
+		} else if (o instanceof PrototypeSupplier s) {
+			return s.getPrototype(this);
+		} else if (o instanceof Boolean) {
+			return root.booleanPrototype;
+		} else if (o instanceof Number) {
+			return root.numberPrototype;
+		} else if (o instanceof CharSequence) {
+			return root.stringPrototype;
+		} else if (o instanceof Class) {
+			return root.classPrototype;
+		} else if (o instanceof Pattern) {
+			return root.regExpPrototype;
+		} else if (o.getClass().isArray()) {
+			return root.arrayPrototype;
+		}
+
+		return getClassPrototype(o.getClass());
+	}
+
+	public Prototype<?> getClassPrototype(Class<?> c) {
+		if (c == Boolean.class) {
+			return root.booleanPrototype;
+		} else if (c == Number.class) {
+			return root.numberPrototype;
+		} else if (c == String.class) {
+			return root.stringPrototype;
+		} else if (c == Class.class) {
+			return root.classPrototype;
+		} else if (c == Map.class || c == HashMap.class || c == LinkedHashMap.class || c == IdentityHashMap.class || c == EnumMap.class) {
+			return root.jsMapPrototype;
+		} else if (c == Set.class || c == HashSet.class || c == LinkedHashSet.class || c == EnumSet.class) {
+			return root.jsSetPrototype;
+		} else if (c == List.class || c == ArrayList.class || c == LinkedList.class) {
+			return root.listPrototype;
+		} else if (c == Collection.class) {
+			return root.collectionPrototype;
+		} else if (c == Iterable.class) {
+			return root.iterablePrototype;
+		} else if (c == Pattern.class) {
+			return root.regExpPrototype;
+		} else if (c.isArray()) {
+			return root.arrayPrototype;
+		}
+
+		var p = root.classPrototypes.get(c);
+
+		if (p == null) {
+			p = new Prototype<>(this, c);
+			root.classPrototypes.put(c, p);
+		}
+
+		return p;
+	}
+
+	public boolean equals(Object left, Object right, boolean shallow) {
+		if (left == right) {
+			return true;
+		} else if (left instanceof Number l && right instanceof Number r) {
+			return Math.abs(l.doubleValue() - r.doubleValue()) < 0.00001D;
+		} else if (left instanceof CharSequence || left instanceof Character || right instanceof CharSequence || right instanceof Character) {
+			return asString(left, false).equals(asString(right, false));
+		} else {
+			var p = getPrototype(left);
+			return p.equals(this, p.cast(left), right, shallow);
+		}
+	}
+
+	public int compareTo(Object left, Object right) {
+		if (left == right || Objects.equals(left, right)) {
+			return 0;
+		} else if (left instanceof Number l && right instanceof Number r) {
+			return Math.abs(l.doubleValue() - r.doubleValue()) < 0.00001D ? 0 : Double.compare(l.doubleValue(), r.doubleValue());
+		} else {
+			var p = getPrototype(right);
+			return p.compareTo(this, p.cast(left), right);
+		}
+	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ScriptValue.java b/src/main/java/dev/latvian/apps/ichor/ScriptValue.java
new file mode 100644
index 0000000..2dffdb6
--- /dev/null
+++ b/src/main/java/dev/latvian/apps/ichor/ScriptValue.java
@@ -0,0 +1,25 @@
+package dev.latvian.apps.ichor;
+
+import dev.latvian.apps.ichor.prototype.Prototype;
+
+import java.util.Objects;
+
+public class ScriptValue {
+	public final Object value;
+	public final Prototype<?> prototype;
+
+	public ScriptValue(Object value, Prototype<?> prototype) {
+		this.value = value;
+		this.prototype = prototype;
+	}
+
+	@Override
+	public String toString() {
+		return "[" + prototype.getPrototypeName() + " " + value + "]";
+	}
+
+	@Override
+	public int hashCode() {
+		return Objects.hashCode(value);
+	}
+}
diff --git a/src/main/java/dev/latvian/apps/ichor/Special.java b/src/main/java/dev/latvian/apps/ichor/Special.java
index b3fc071..8168cad 100644
--- a/src/main/java/dev/latvian/apps/ichor/Special.java
+++ b/src/main/java/dev/latvian/apps/ichor/Special.java
@@ -16,13 +16,15 @@ public static boolean isInvalid(@Nullable Object o) {
 	}
 
 	public final Prototype<?> prototype;
+	public final ScriptValue scriptValue;
 
 	private Special(String name) {
-		prototype = new Prototype<>(null, name, Void.TYPE);
+		this.prototype = new Prototype<>(null, name, Void.TYPE);
+		this.scriptValue = new ScriptValue(null, prototype);
 	}
 
 	@Override
-	public Prototype<?> getPrototype(Context cx, Scope scope) {
+	public Prototype<?> getPrototype(Scope scope) {
 		return prototype;
 	}
 
@@ -42,22 +44,22 @@ public String toString() {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
+	public Object eval(Scope scope) {
 		return this == UNDEFINED ? this : null;
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
+	public boolean evalBoolean(Scope scope) {
 		return false;
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
+	public double evalDouble(Scope scope) {
 		return Double.NaN;
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
+	public int evalInt(Scope scope) {
 		return 0;
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/TypeAdapter.java b/src/main/java/dev/latvian/apps/ichor/TypeAdapter.java
index fd985d2..701f58b 100644
--- a/src/main/java/dev/latvian/apps/ichor/TypeAdapter.java
+++ b/src/main/java/dev/latvian/apps/ichor/TypeAdapter.java
@@ -1,13 +1,13 @@
 package dev.latvian.apps.ichor;
 
 public interface TypeAdapter {
-	default <T> boolean canAdapt(Context cx, Class<T> type) {
+	default <T> boolean canAdapt(Scope scope, Class<T> type) {
 		if (type != null && type.isInterface()) {
-			return cx.getClassPrototype(type).isSingleMethodInterface();
+			return scope.getClassPrototype(type).isSingleMethodInterface();
 		}
 
 		return false;
 	}
 
-	<T> T adapt(Context cx, Scope scope, Class<T> type);
+	<T> T adapt(Scope scope, Class<T> type);
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/annotation/Hidden.java b/src/main/java/dev/latvian/apps/ichor/annotation/Hidden.java
index dfbd5e8..368bbdb 100644
--- a/src/main/java/dev/latvian/apps/ichor/annotation/Hidden.java
+++ b/src/main/java/dev/latvian/apps/ichor/annotation/Hidden.java
@@ -11,11 +11,10 @@
  * If added to a member (field or method), they will act as undefined / non-existant.<br>
  * If added to a class, all members will be hidden.<br>
  * If added to a constructor, new Type() will be hidden.<br>
- * If added to a package, all classes, members and constructors will be hidden.<br>
- * For fields <code>transient</code> keyword can be used instead of this annotation.
+ * For fields <code>transient</code> keyword can (and is encouraged to) be used instead of this annotation.
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PACKAGE})
+@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
 public @interface Hidden {
 }
\ No newline at end of file
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstAwait.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstAwait.java
index 158fb30..ae96b90 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstAwait.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstAwait.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
@@ -23,8 +22,8 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var e = cx.eval(scope, future);
+	public Object eval(Scope scope) {
+		var e = scope.eval(future);
 
 		if (Special.isInvalid(e)) {
 			return e;
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstCall.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstCall.java
index 8d4cede..f84acac 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstCall.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstCall.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.ast.expression;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
@@ -67,20 +66,20 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var func = cx.eval(scope, function);
+	public Object eval(Scope scope) {
+		var func = scope.eval(function);
 
 		if (Special.isInvalid(func)) {
 			throw new FunctionNotFoundError(function);
 		} else if (!(func instanceof Callable)) {
-			throw new CallError(function, func, cx.getPrototype(scope, func));
+			throw new CallError(function, func, scope.getPrototype(func));
 		}
 
-		var args = ((Callable) func).evalArgs(cx, scope, arguments);
-		var r = ((Callable) func).call(cx, scope, args, hasNew);
+		var args = ((Callable) func).evalArgs(scope, arguments);
+		var r = ((Callable) func).call(scope, args, hasNew);
 
 		if (r == Special.NOT_FOUND) {
-			throw new CallError(function, func, cx.getPrototype(scope, func));
+			throw new CallError(function, func, scope.getPrototype(func));
 		}
 
 		return r;
@@ -122,13 +121,13 @@ public AstToString(Object from) {
 		}
 
 		@Override
-		public Object eval(Context cx, Scope scope) {
-			return cx.asString(scope, from, false);
+		public Object eval(Scope scope) {
+			return scope.asString(from, false);
 		}
 
 		@Override
-		public void evalString(Context cx, Scope scope, StringBuilder builder) {
-			cx.asString(scope, from, builder, false);
+		public void evalString(Scope scope, StringBuilder builder) {
+			scope.asString(from, builder, false);
 		}
 
 		@Override
@@ -146,18 +145,18 @@ public AstHashCode(Object from) {
 		}
 
 		@Override
-		public Object eval(Context cx, Scope scope) {
-			return evalInt(cx, scope);
+		public Object eval(Scope scope) {
+			return evalInt(scope);
 		}
 
 		@Override
-		public double evalDouble(Context cx, Scope scope) {
-			return evalInt(cx, scope);
+		public double evalDouble(Scope scope) {
+			return evalInt(scope);
 		}
 
 		@Override
-		public int evalInt(Context cx, Scope scope) {
-			return Objects.hashCode(cx.eval(scope, from));
+		public int evalInt(Scope scope) {
+			return Objects.hashCode(scope.eval(from));
 		}
 
 		@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstClassFunction.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstClassFunction.java
index fcec348..229d501 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstClassFunction.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstClassFunction.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.statement.AstClass;
@@ -21,7 +20,7 @@ public AstClassFunction(AstClass owner, AstParam[] params, Interpretable body, i
 	}
 
 	@Override
-	public ClassFunctionInstance eval(Context cx, Scope scope) {
-		return new ClassFunctionInstance(this, cx, scope);
+	public ClassFunctionInstance eval(Scope scope) {
+		return new ClassFunctionInstance(this, scope);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstClassPrototype.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstClassPrototype.java
index 97cfe7b..8c05c51 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstClassPrototype.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstClassPrototype.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -14,15 +13,15 @@ public AstClassPrototype(Object from) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var self = cx.eval(scope, from);
+	public Object eval(Scope scope) {
+		var self = scope.eval(from);
 
 		if (self == null) {
 			return Special.UNDEFINED;
 		} else if (self instanceof PrototypeSupplier ps) {
-			return ps.getPrototype(cx, scope);
+			return ps.getPrototype(scope);
 		} else {
-			return cx.getClassPrototype(self.getClass());
+			return scope.getClassPrototype(self.getClass());
 		}
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstDelete.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstDelete.java
index bd33b98..a3b0763 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstDelete.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstDelete.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -20,8 +19,8 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return get.delete(cx, scope);
+	public Object eval(Scope scope) {
+		return get.delete(scope);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstFunction.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstFunction.java
index 9fe82a2..dfad894 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstFunction.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstFunction.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -89,8 +88,8 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public FunctionInstance eval(Context cx, Scope scope) {
-		return new FunctionInstance(this, cx, scope);
+	public FunctionInstance eval(Scope scope) {
+		return new FunctionInstance(this, scope);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetBase.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetBase.java
index 049b082..017b6d5 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetBase.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetBase.java
@@ -1,10 +1,9 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public abstract class AstGetBase extends AstExpression {
-	public abstract void set(Context cx, Scope scope, Object value);
+	public abstract void set(Scope scope, Object value);
 
-	public abstract boolean delete(Context cx, Scope scope);
+	public abstract boolean delete(Scope scope);
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByEvaluable.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByEvaluable.java
index 79c94f8..abe6d11 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByEvaluable.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByEvaluable.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
@@ -25,10 +24,10 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var k = cx.eval(scope, key);
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
+	public Object eval(Scope scope) {
+		var k = scope.eval(key);
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
 
 		Object r;
 
@@ -39,14 +38,14 @@ public Object eval(Context cx, Scope scope) {
 				throw new IndexedMemberNotFoundError(ki, p, self).pos(this);
 			}
 
-			r = p.getLocal(cx, scope, p.cast(self), ki);
+			r = p.getLocal(scope, p.cast(self), ki);
 
 			if (r == Special.NOT_FOUND) {
 				throw new IndexedMemberNotFoundError(ki, p, self).pos(this);
 			}
 		} else {
-			var ks = cx.asString(scope, k, false);
-			r = p.getInternal(cx, scope, self, ks);
+			var ks = scope.asString(k, false);
+			r = p.getInternal(scope, self, ks);
 
 			if (r == Special.NOT_FOUND) {
 				throw new NamedMemberNotFoundError(ks, p, self).pos(this);
@@ -57,10 +56,10 @@ public Object eval(Context cx, Scope scope) {
 	}
 
 	@Override
-	public void set(Context cx, Scope scope, Object value) {
-		var k = cx.eval(scope, key);
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
+	public void set(Scope scope, Object value) {
+		var k = scope.eval(key);
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
 
 		if (k instanceof Number n) {
 			var ki = n.intValue();
@@ -69,23 +68,23 @@ public void set(Context cx, Scope scope, Object value) {
 				throw new IndexedMemberNotFoundError(ki, p, self).pos(this);
 			}
 
-			if (!p.setLocal(cx, scope, p.cast(self), ki, value)) {
+			if (!p.setLocal(scope, p.cast(self), ki, value)) {
 				throw new IndexedMemberNotFoundError(ki, p, self).pos(this);
 			}
 		} else {
-			var ks = cx.asString(scope, k, false);
+			var ks = scope.asString(k, false);
 
-			if (!(self == p ? p.setStatic(cx, scope, ks, value) : p.setLocal(cx, scope, p.cast(self), ks, value))) {
+			if (!(self == p ? p.setStatic(scope, ks, value) : p.setLocal(scope, p.cast(self), ks, value))) {
 				throw new NamedMemberNotFoundError(ks, p, self).pos(this);
 			}
 		}
 	}
 
 	@Override
-	public boolean delete(Context cx, Scope scope) {
-		var k = cx.eval(scope, key);
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
+	public boolean delete(Scope scope) {
+		var k = scope.eval(key);
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
 
 		if (k instanceof Number n) {
 			var ki = n.intValue();
@@ -94,15 +93,15 @@ public boolean delete(Context cx, Scope scope) {
 				throw new IndexedMemberNotFoundError(ki, p, self).pos(this);
 			}
 
-			return p.deleteLocal(cx, scope, p.cast(self), ki);
+			return p.deleteLocal(scope, p.cast(self), ki);
 		} else {
-			var ks = cx.asString(scope, k, false);
+			var ks = scope.asString(k, false);
 
 			if (self == p) {
 				throw new NamedMemberNotFoundError(ks, p, self).pos(this);
 			}
 
-			return p.deleteLocal(cx, scope, p.cast(self), ks);
+			return p.deleteLocal(scope, p.cast(self), ks);
 		}
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByIndex.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByIndex.java
index f39ae14..c21b3ba 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByIndex.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByIndex.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -23,15 +22,15 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
+	public Object eval(Scope scope) {
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
 
 		if (self == p) {
 			throw new IndexedMemberNotFoundError(index, p, self).pos(this);
 		}
 
-		var r = p.getLocal(cx, scope, p.cast(self), index);
+		var r = p.getLocal(scope, p.cast(self), index);
 
 		if (r == Special.NOT_FOUND) {
 			throw new IndexedMemberNotFoundError(index, p, self).pos(this);
@@ -41,28 +40,28 @@ public Object eval(Context cx, Scope scope) {
 	}
 
 	@Override
-	public void set(Context cx, Scope scope, Object value) {
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
+	public void set(Scope scope, Object value) {
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
 
 		if (self == p) {
 			throw new IndexedMemberNotFoundError(index, p, self).pos(this);
 		}
 
-		if (!p.setLocal(cx, scope, p.cast(self), index, value)) {
+		if (!p.setLocal(scope, p.cast(self), index, value)) {
 			throw new IndexedMemberNotFoundError(index, p, self).pos(this);
 		}
 	}
 
 	@Override
-	public boolean delete(Context cx, Scope scope) {
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
+	public boolean delete(Scope scope) {
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
 
 		if (self == p) {
 			throw new IndexedMemberNotFoundError(index, p, self).pos(this);
 		}
 
-		return p.deleteLocal(cx, scope, p.cast(self), index);
+		return p.deleteLocal(scope, p.cast(self), index);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByName.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByName.java
index c030e32..0db8e6f 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByName.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByName.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.ast.expression;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
@@ -36,10 +35,10 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
-		var r = p.getInternal(cx, scope, self, name);
+	public Object eval(Scope scope) {
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
+		var r = p.getInternal(scope, self, name);
 
 		if (r == Special.NOT_FOUND) {
 			throw new NamedMemberNotFoundError(name, p, self).pos(this);
@@ -49,25 +48,25 @@ public Object eval(Context cx, Scope scope) {
 	}
 
 	@Override
-	public void set(Context cx, Scope scope, Object value) {
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
+	public void set(Scope scope, Object value) {
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
 
-		if (!(self == p ? p.setStatic(cx, scope, name, value) : p.setLocal(cx, scope, p.cast(self), name, value))) {
+		if (!(self == p ? p.setStatic(scope, name, value) : p.setLocal(scope, p.cast(self), name, value))) {
 			throw new NamedMemberNotFoundError(name, p, self).pos(this);
 		}
 	}
 
 	@Override
-	public boolean delete(Context cx, Scope scope) {
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
+	public boolean delete(Scope scope) {
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
 
 		if (self == p) {
 			throw new NamedMemberNotFoundError(name, p, self).pos(this);
 		}
 
-		return p.deleteLocal(cx, scope, p.cast(self), name);
+		return p.deleteLocal(scope, p.cast(self), name);
 	}
 
 	@Override
@@ -76,7 +75,7 @@ public Object optimize(Parser parser) {
 
 		// Is this correct? So far seems to work
 		if (from instanceof Prototype<?> p) {
-			var m = p.getStatic(parser.getContext(), parser.getRootScope(), name);
+			var m = p.getStatic(parser.getRootScope(), name);
 
 			if (m == Special.NOT_FOUND) {
 				throw new NamedMemberNotFoundError(name, p, p).pos(this);
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByNameOptional.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByNameOptional.java
index e49bec5..ec20bb7 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByNameOptional.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetByNameOptional.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -18,10 +17,10 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var self = evalSelf(cx, scope);
-		var p = cx.getPrototype(scope, self);
-		var r = p.getInternal(cx, scope, self, name);
+	public Object eval(Scope scope) {
+		var self = evalSelf(scope);
+		var p = scope.getPrototype(self);
+		var r = p.getInternal(scope, self, name);
 
 		if (Special.isInvalid(r)) {
 			return Special.UNDEFINED;
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetFrom.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetFrom.java
index 9ba3c94..e3d71d9 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetFrom.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetFrom.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import org.jetbrains.annotations.Nullable;
@@ -13,8 +12,8 @@ public AstGetFrom(Object from) {
 	}
 
 	@Nullable
-	public Object evalSelf(Context cx, Scope scope) {
-		return cx.eval(scope, from);
+	public Object evalSelf(Scope scope) {
+		return scope.eval(from);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetScopeMember.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetScopeMember.java
index 737c843..2713f14 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetScopeMember.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstGetScopeMember.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
@@ -19,17 +18,17 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
+	public Object eval(Scope scope) {
 		return scope.getMember(name);
 	}
 
 	@Override
-	public void set(Context cx, Scope scope, Object value) {
+	public void set(Scope scope, Object value) {
 		scope.setMember(name, value);
 	}
 
 	@Override
-	public boolean delete(Context cx, Scope scope) {
+	public boolean delete(Scope scope) {
 		scope.deleteDeclaredMember(name);
 		return true;
 	}
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstList.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstList.java
index 32c3717..31bb976 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstList.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstList.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Evaluable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -39,12 +38,12 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
+	public Object eval(Scope scope) {
 		var list = new ArrayList<>(values.size());
 
 		for (var o : values) {
 			if (o instanceof AstSpread spread) {
-				var s = cx.eval(scope, spread.value);
+				var s = scope.eval(spread.value);
 
 				if (s instanceof Iterable<?> itr) {
 					for (var o1 : itr) {
@@ -54,7 +53,7 @@ public Object eval(Context cx, Scope scope) {
 					throw new SpreadError().pos(pos);
 				}
 			} else {
-				list.add(cx.eval(scope, o));
+				list.add(scope.eval(o));
 			}
 		}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstMap.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstMap.java
index 03c7ffa..468ec94 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstMap.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstMap.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Evaluable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -69,14 +68,14 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
+	public Object eval(Scope scope) {
 		var map = new LinkedHashMap<>(values.size());
 
 		for (var entry : values.entrySet()) {
 			var o = entry.getValue();
 
 			if (o instanceof AstSpread spread) {
-				var s = cx.eval(scope, spread.value);
+				var s = scope.eval(spread.value);
 
 				if (s instanceof Map<?, ?> map1) {
 					map.putAll(map1);
@@ -84,7 +83,7 @@ public Object eval(Context cx, Scope scope) {
 					throw new SpreadError().pos(pos);
 				}
 			} else {
-				map.put(entry.getKey(), cx.eval(scope, o));
+				map.put(entry.getKey(), scope.eval(o));
 			}
 		}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstObjectPrototype.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstObjectPrototype.java
index c3e6678..04661ba 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstObjectPrototype.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstObjectPrototype.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -14,15 +13,15 @@ public AstObjectPrototype(Object from) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var self = cx.eval(scope, from);
+	public Object eval(Scope scope) {
+		var self = scope.eval(from);
 
 		if (self == null) {
 			return Special.UNDEFINED;
 		} else if (self instanceof PrototypeSupplier ps) {
-			return ps.getPrototype(cx, scope);
+			return ps.getPrototype(scope);
 		} else {
-			return cx.getPrototype(scope, self);
+			return scope.getPrototype(self);
 		}
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstSet.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstSet.java
index 7d22219..5680b36 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstSet.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstSet.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -22,9 +21,9 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var v = cx.eval(scope, value);
-		get.set(cx, scope, v);
+	public Object eval(Scope scope) {
+		var v = scope.eval(value);
+		get.set(scope, v);
 		return v;
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTempExpression.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTempExpression.java
index df38bfc..65a0456 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTempExpression.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTempExpression.java
@@ -1,12 +1,11 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 
 public abstract class AstTempExpression extends AstExpression {
 	@Override
-	public Object eval(Context cx, Scope scope) {
+	public Object eval(Scope scope) {
 		return Special.NOT_FOUND;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTemplateLiteral.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTemplateLiteral.java
index 65eb51e..2728a76 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTemplateLiteral.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTemplateLiteral.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.ast.expression;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Evaluable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -41,9 +40,9 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public String eval(Context cx, Scope scope) {
+	public String eval(Scope scope) {
 		if (tag != null) {
-			var func = cx.eval(scope, tag);
+			var func = scope.eval(tag);
 
 			if (func instanceof Callable c) {
 				var args = new ArrayList<>((int) Math.floor(parts.length / 2D));
@@ -54,26 +53,26 @@ public String eval(Context cx, Scope scope) {
 					if (part instanceof CharSequence str) {
 						strings.add(str.toString());
 					} else {
-						args.add(cx.eval(scope, part));
+						args.add(scope.eval(part));
 					}
 				}
 
-				return cx.asString(scope, c.call(cx, scope, args.toArray(), false), false);
+				return scope.asString(c.call(scope, args.toArray(), false), false);
 			} else {
-				throw new AstCall.CallError(tag, func, cx.getPrototype(scope, func));
+				throw new AstCall.CallError(tag, func, scope.getPrototype(func));
 			}
 		}
 
 		var builder = new StringBuilder();
-		evalString(cx, scope, builder);
+		evalString(scope, builder);
 		return builder.toString();
 	}
 
 	@Override
-	public void evalString(Context cx, Scope scope, StringBuilder builder) {
+	public void evalString(Scope scope, StringBuilder builder) {
 		for (var part : parts) {
 			if (part instanceof Evaluable eval) {
-				eval.evalString(cx, scope, builder);
+				eval.evalString(scope, builder);
 			} else {
 				builder.append(part);
 			}
@@ -81,26 +80,26 @@ public void evalString(Context cx, Scope scope, StringBuilder builder) {
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
+	public double evalDouble(Scope scope) {
 		try {
-			return IchorUtils.parseNumber(eval(cx, scope)).doubleValue();
+			return IchorUtils.parseNumber(eval(scope)).doubleValue();
 		} catch (Exception ex) {
 			return Double.NaN;
 		}
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
+	public int evalInt(Scope scope) {
 		try {
-			return IchorUtils.parseNumber(eval(cx, scope)).intValue();
+			return IchorUtils.parseNumber(eval(scope)).intValue();
 		} catch (Exception ex) {
 			throw new InternalScriptError(ex);
 		}
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return !eval(cx, scope).isEmpty();
+	public boolean evalBoolean(Scope scope) {
+		return !eval(scope).isEmpty();
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTernary.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTernary.java
index ddf052f..305c95f 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTernary.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTernary.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -22,8 +21,8 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return cx.asBoolean(scope, condition) ? cx.eval(scope, ifTrue) : cx.eval(scope, ifFalse);
+	public Object eval(Scope scope) {
+		return scope.asBoolean(condition) ? scope.eval(ifTrue) : scope.eval(ifFalse);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstType.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstType.java
index 0d07891..dda859f 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstType.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstType.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AppendableAst;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -8,18 +7,17 @@
 public abstract class AstType implements AppendableAst {
 	@FunctionalInterface
 	public interface CastFunc {
-		CastFunc NONE = (cx, scope, from) -> from;
+		CastFunc NONE = (scope, from) -> from;
 
-		Object cast(Context cx, Scope scope, Object from);
+		Object cast(Scope scope, Object from);
 	}
 
 	public static class Generic extends AstType {
-
 		public static final Generic ANY = new Generic("any", CastFunc.NONE);
 		public static final Generic VOID = new Generic("void", CastFunc.NONE);
-		public static final Generic BOOLEAN = new Generic("boolean", Context::asBoolean);
-		public static final Generic NUMBER = new Generic("number", Context::asNumber);
-		public static final Generic STRING = new Generic("string", (cx, scope, from) -> cx.asString(scope, from, false));
+		public static final Generic BOOLEAN = new Generic("boolean", Scope::asBoolean);
+		public static final Generic NUMBER = new Generic("number", Scope::asNumber);
+		public static final Generic STRING = new Generic("string", (scope, from) -> scope.asString(from, false));
 		public static final Generic FUNCTION = new Generic("function", CastFunc.NONE);
 		public static final Generic OBJECT = new Generic("object", CastFunc.NONE);
 		public static final Generic BIGINT = new Generic("bigint", CastFunc.NONE);
@@ -39,8 +37,8 @@ public void append(AstStringBuilder builder) {
 		}
 
 		@Override
-		public Object cast(Context cx, Scope scope, Object from) {
-			return cast.cast(cx, scope, from);
+		public Object cast(Scope scope, Object from) {
+			return cast.cast(scope, from);
 		}
 	}
 
@@ -102,7 +100,7 @@ public void append(AstStringBuilder builder) {
 		}
 	}
 
-	public Object cast(Context cx, Scope scope, Object from) {
+	public Object cast(Scope scope, Object from) {
 		return from;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTypeOf.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTypeOf.java
index 5a3386f..334442b 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTypeOf.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/AstTypeOf.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.ast.expression;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
@@ -17,8 +16,8 @@ public AstTypeOf(Object of) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var o = cx.eval(scope, of);
+	public Object eval(Scope scope) {
+		var o = scope.eval(of);
 
 		if (o == Special.UNDEFINED) {
 			return "undefined";
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstAdd.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstAdd.java
index f5151bf..eb3c4f9 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstAdd.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstAdd.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.error.ScriptError;
@@ -22,14 +21,14 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var l = cx.eval(scope, left);
-		var r = cx.eval(scope, right);
+	public Object eval(Scope scope) {
+		var l = scope.eval(left);
+		var r = scope.eval(right);
 
 		if (l instanceof CharSequence || l instanceof Character || r instanceof CharSequence || r instanceof Character) {
 			var sb = new StringBuilder();
-			cx.asString(scope, l, sb, false);
-			cx.asString(scope, r, sb, false);
+			scope.asString(l, sb, false);
+			scope.asString(r, sb, false);
 			return sb.toString();
 		} else if (l instanceof Number && r instanceof Number) {
 			return ((Number) l).doubleValue() + ((Number) r).doubleValue();
@@ -39,8 +38,8 @@ public Object eval(Context cx, Scope scope) {
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return cx.asDouble(scope, left) + cx.asDouble(scope, right);
+	public double evalDouble(Scope scope) {
+		return scope.asDouble(left) + scope.asDouble(right);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstAnd.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstAnd.java
index cd46943..5533559 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstAnd.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstAnd.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstAnd extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.asBoolean(scope, left) && cx.asBoolean(scope, right);
+	public boolean evalBoolean(Scope scope) {
+		return scope.asBoolean(left) && scope.asBoolean(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBinaryBoolean.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBinaryBoolean.java
index 17041a4..24b3b71 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBinaryBoolean.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBinaryBoolean.java
@@ -1,29 +1,28 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public abstract class AstBinaryBoolean extends AstBinary {
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalBoolean(cx, scope);
+	public Object eval(Scope scope) {
+		return evalBoolean(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalBoolean(cx, scope) ? 1D : 0D;
+	public double evalDouble(Scope scope) {
+		return evalBoolean(scope) ? 1D : 0D;
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return evalBoolean(cx, scope) ? 1 : 0;
+	public int evalInt(Scope scope) {
+		return evalBoolean(scope) ? 1 : 0;
 	}
 
 	@Override
-	public abstract boolean evalBoolean(Context cx, Scope scope);
+	public abstract boolean evalBoolean(Scope scope);
 
 	@Override
-	public void evalString(Context cx, Scope scope, StringBuilder builder) {
-		builder.append(evalBoolean(cx, scope));
+	public void evalString(Scope scope, StringBuilder builder) {
+		builder.append(evalBoolean(scope));
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBitwiseAnd.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBitwiseAnd.java
index f1fe661..8d1060d 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBitwiseAnd.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBitwiseAnd.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstBitwiseAnd extends AstBinary {
@@ -10,22 +9,22 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public Object eval(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public double evalDouble(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return cx.asInt(scope, left) & cx.asInt(scope, right);
+	public int evalInt(Scope scope) {
+		return scope.asInt(left) & scope.asInt(right);
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.asBoolean(scope, left) & cx.asBoolean(scope, right);
+	public boolean evalBoolean(Scope scope) {
+		return scope.asBoolean(left) & scope.asBoolean(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBitwiseOr.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBitwiseOr.java
index 4f5afe1..7cde14c 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBitwiseOr.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstBitwiseOr.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstBitwiseOr extends AstBinary {
@@ -10,22 +9,22 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public Object eval(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public double evalDouble(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return cx.asInt(scope, left) | cx.asInt(scope, right);
+	public int evalInt(Scope scope) {
+		return scope.asInt(left) | scope.asInt(right);
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.asBoolean(scope, left) | cx.asBoolean(scope, right);
+	public boolean evalBoolean(Scope scope) {
+		return scope.asBoolean(left) | scope.asBoolean(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstDiv.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstDiv.java
index a1ef171..22131a5 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstDiv.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstDiv.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 
@@ -11,13 +10,13 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalDouble(cx, scope);
+	public Object eval(Scope scope) {
+		return evalDouble(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return cx.asDouble(scope, left) / cx.asDouble(scope, right);
+	public double evalDouble(Scope scope) {
+		return scope.asDouble(left) / scope.asDouble(right);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstEq.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstEq.java
index 489bd71..a4916dd 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstEq.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstEq.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstEq extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.equals(scope, cx.eval(scope, left), cx.eval(scope, right), false);
+	public boolean evalBoolean(Scope scope) {
+		return scope.equals(scope.eval(left), scope.eval(right), false);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstGt.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstGt.java
index f1777d5..ab9f2eb 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstGt.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstGt.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstGt extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.compareTo(scope, cx.eval(scope, left), cx.eval(scope, right)) > 0;
+	public boolean evalBoolean(Scope scope) {
+		return scope.compareTo(scope.eval(left), scope.eval(right)) > 0;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstGte.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstGte.java
index b35e16e..89b9dcb 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstGte.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstGte.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstGte extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.compareTo(scope, cx.eval(scope, left), cx.eval(scope, right)) >= 0;
+	public boolean evalBoolean(Scope scope) {
+		return scope.compareTo(scope.eval(left), scope.eval(right)) >= 0;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstIn.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstIn.java
index 41ad36a..5459c1c 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstIn.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstIn.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstIn extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
+	public boolean evalBoolean(Scope scope) {
 		//TODO: Implement
 		return false;
 	}
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstInstanceOf.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstInstanceOf.java
index 4a08760..b392f7c 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstInstanceOf.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstInstanceOf.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstInstanceOf extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
+	public boolean evalBoolean(Scope scope) {
 		//TODO: Implement
 		return false;
 	}
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLsh.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLsh.java
index 8a13d8f..533fc3c 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLsh.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLsh.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstLsh extends AstBinary {
@@ -10,17 +9,17 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public Object eval(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public double evalDouble(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return cx.asInt(scope, left) << cx.asInt(scope, right);
+	public int evalInt(Scope scope) {
+		return scope.asInt(left) << scope.asInt(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLt.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLt.java
index cf17158..f76eb41 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLt.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLt.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstLt extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.compareTo(scope, cx.eval(scope, left), cx.eval(scope, right)) < 0;
+	public boolean evalBoolean(Scope scope) {
+		return scope.compareTo(scope.eval(left), scope.eval(right)) < 0;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLte.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLte.java
index 32f2f4e..140cb3a 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLte.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstLte.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstLte extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.compareTo(scope, cx.eval(scope, left), cx.eval(scope, right)) <= 0;
+	public boolean evalBoolean(Scope scope) {
+		return scope.compareTo(scope.eval(left), scope.eval(right)) <= 0;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstMod.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstMod.java
index 5c40088..e9c8a94 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstMod.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstMod.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstMod extends AstBinary {
@@ -10,12 +9,12 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalDouble(cx, scope);
+	public Object eval(Scope scope) {
+		return evalDouble(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return cx.asDouble(scope, left) % cx.asDouble(scope, right);
+	public double evalDouble(Scope scope) {
+		return scope.asDouble(left) % scope.asDouble(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstMul.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstMul.java
index ba6826d..f4152f5 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstMul.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstMul.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 
@@ -11,13 +10,13 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalDouble(cx, scope);
+	public Object eval(Scope scope) {
+		return evalDouble(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return cx.asDouble(scope, left) * cx.asDouble(scope, right);
+	public double evalDouble(Scope scope) {
+		return scope.asDouble(left) * scope.asDouble(right);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstNc.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstNc.java
index 8a26ba5..14fb629 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstNc.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstNc.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 
@@ -11,8 +10,8 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		var l = cx.eval(scope, left);
-		return Special.isInvalid(l) ? cx.eval(scope, right) : l;
+	public Object eval(Scope scope) {
+		var l = scope.eval(left);
+		return Special.isInvalid(l) ? scope.eval(right) : l;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstNeq.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstNeq.java
index 492302d..a07a07a 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstNeq.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstNeq.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstNeq extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return !cx.equals(scope, cx.eval(scope, left), cx.eval(scope, right), false);
+	public boolean evalBoolean(Scope scope) {
+		return !scope.equals(scope.eval(left), scope.eval(right), false);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstOr.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstOr.java
index 3b49725..67d24c2 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstOr.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstOr.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstOr extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.asBoolean(scope, left) || cx.asBoolean(scope, right);
+	public boolean evalBoolean(Scope scope) {
+		return scope.asBoolean(left) || scope.asBoolean(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstPow.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstPow.java
index 08c1413..994209f 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstPow.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstPow.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 
@@ -11,13 +10,13 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalDouble(cx, scope);
+	public Object eval(Scope scope) {
+		return evalDouble(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return Math.pow(cx.asDouble(scope, left), cx.asDouble(scope, right));
+	public double evalDouble(Scope scope) {
+		return Math.pow(scope.asDouble(left), scope.asDouble(right));
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstRsh.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstRsh.java
index 7f19d15..ffb0d23 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstRsh.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstRsh.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstRsh extends AstBinary {
@@ -10,17 +9,17 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public Object eval(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public double evalDouble(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return cx.asInt(scope, left) >> cx.asInt(scope, right);
+	public int evalInt(Scope scope) {
+		return scope.asInt(left) >> scope.asInt(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSeq.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSeq.java
index 4eee71f..34dd60e 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSeq.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSeq.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstSeq extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.equals(scope, cx.eval(scope, left), cx.eval(scope, right), true);
+	public boolean evalBoolean(Scope scope) {
+		return scope.equals(scope.eval(left), scope.eval(right), true);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSneq.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSneq.java
index 11dd17a..2354666 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSneq.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSneq.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstSneq extends AstBinaryBoolean {
@@ -10,7 +9,7 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return !cx.equals(scope, cx.eval(scope, left), cx.eval(scope, right), true);
+	public boolean evalBoolean(Scope scope) {
+		return !scope.equals(scope.eval(left), scope.eval(right), true);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSub.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSub.java
index 564cbf1..1afd449 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSub.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstSub.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 
@@ -11,13 +10,13 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalDouble(cx, scope);
+	public Object eval(Scope scope) {
+		return evalDouble(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return cx.asDouble(scope, left) - cx.asDouble(scope, right);
+	public double evalDouble(Scope scope) {
+		return scope.asDouble(left) - scope.asDouble(right);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstUrsh.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstUrsh.java
index 7e08238..c7bb0d2 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstUrsh.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstUrsh.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstUrsh extends AstBinary {
@@ -10,17 +9,17 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public Object eval(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public double evalDouble(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return cx.asInt(scope, left) >>> cx.asInt(scope, right);
+	public int evalInt(Scope scope) {
+		return scope.asInt(left) >>> scope.asInt(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstXor.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstXor.java
index 55ffa83..4a1fa46 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstXor.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/binary/AstXor.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.binary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public class AstXor extends AstBinary {
@@ -10,22 +9,22 @@ public void appendSymbol(StringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public Object eval(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public double evalDouble(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return cx.asInt(scope, left) ^ cx.asInt(scope, right);
+	public int evalInt(Scope scope) {
+		return scope.asInt(left) ^ scope.asInt(right);
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return cx.asBoolean(scope, left) ^ cx.asBoolean(scope, right);
+	public boolean evalBoolean(Scope scope) {
+		return scope.asBoolean(left) ^ scope.asBoolean(right);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstAdditive1.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstAdditive1.java
index d7b3cbb..b2233fd 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstAdditive1.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstAdditive1.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.unary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 import dev.latvian.apps.ichor.ast.expression.AstGetBase;
@@ -22,15 +21,15 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalDouble(cx, scope);
+	public Object eval(Scope scope) {
+		return evalDouble(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		double o = cx.asDouble(scope, node);
+	public double evalDouble(Scope scope) {
+		double o = scope.asDouble(node);
 		double n = isAdd() ? o + 1D : o - 1D;
-		((AstGetBase) node).set(cx, scope, n);
+		((AstGetBase) node).set(scope, n);
 		return isLeft() ? n : o;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstBitwiseNot.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstBitwiseNot.java
index 7e44c14..e3bf2b4 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstBitwiseNot.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstBitwiseNot.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.unary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -13,18 +12,18 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public Object eval(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public double evalDouble(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return ~cx.asInt(scope, node);
+	public int evalInt(Scope scope) {
+		return ~scope.asInt(node);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstNegate.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstNegate.java
index 6e3e2fa..497d1d0 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstNegate.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstNegate.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.unary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -13,18 +12,18 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalDouble(cx, scope);
+	public Object eval(Scope scope) {
+		return evalDouble(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return -cx.asDouble(scope, node);
+	public double evalDouble(Scope scope) {
+		return -scope.asDouble(node);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return -cx.asInt(scope, node);
+	public int evalInt(Scope scope) {
+		return -scope.asInt(node);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstNot.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstNot.java
index 37eff2d..df0e246 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstNot.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstNot.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.unary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -13,23 +12,23 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalBoolean(cx, scope);
+	public Object eval(Scope scope) {
+		return evalBoolean(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return evalInt(cx, scope);
+	public double evalDouble(Scope scope) {
+		return evalInt(scope);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return cx.asBoolean(scope, node) ? 0 : 1;
+	public int evalInt(Scope scope) {
+		return scope.asBoolean(node) ? 0 : 1;
 	}
 
 	@Override
-	public boolean evalBoolean(Context cx, Scope scope) {
-		return !cx.asBoolean(scope, node);
+	public boolean evalBoolean(Scope scope) {
+		return !scope.asBoolean(node);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstPositive.java b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstPositive.java
index 18d6593..d616977 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstPositive.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/expression/unary/AstPositive.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.expression.unary;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -13,18 +12,18 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public Object eval(Context cx, Scope scope) {
-		return evalDouble(cx, scope);
+	public Object eval(Scope scope) {
+		return evalDouble(scope);
 	}
 
 	@Override
-	public double evalDouble(Context cx, Scope scope) {
-		return cx.asDouble(scope, node);
+	public double evalDouble(Scope scope) {
+		return scope.asDouble(node);
 	}
 
 	@Override
-	public int evalInt(Context cx, Scope scope) {
-		return cx.asInt(scope, node);
+	public int evalInt(Scope scope) {
+		return scope.asInt(node);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstBlock.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstBlock.java
index 329cb3c..9609860 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstBlock.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstBlock.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -35,12 +34,12 @@ public boolean handle(ExitType type) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		var s = scope.push();
 
 		for (var statement : interpretable) {
 			try {
-				statement.interpretSafe(cx, s);
+				statement.interpretSafe(s);
 			} catch (BreakExit exit) {
 				if (exit.stop == this) {
 					break;
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstBreak.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstBreak.java
index 4d2e395..096e48a 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstBreak.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstBreak.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 import dev.latvian.apps.ichor.exit.BreakExit;
@@ -25,7 +24,7 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		throw new BreakExit(stop);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstClass.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstClass.java
index e28f473..9537122 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstClass.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstClass.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -63,7 +62,7 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		scope.addImmutable(name, new ClassPrototype(this, scope));
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstContinue.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstContinue.java
index 7744dd1..115361d 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstContinue.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstContinue.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 import dev.latvian.apps.ichor.exit.ContinueExit;
@@ -25,7 +24,7 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		throw new ContinueExit(stop);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstDebugger.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstDebugger.java
index e4445b2..843d6a9 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstDebugger.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstDebugger.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 
@@ -11,7 +10,7 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
-		cx.onDebugger(scope);
+	public void interpret(Scope scope) {
+		scope.root.context.onDebugger(scope);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstDoWhile.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstDoWhile.java
index 852a542..f87396e 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstDoWhile.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstDoWhile.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 import dev.latvian.apps.ichor.exit.BreakExit;
@@ -28,11 +27,11 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		do {
 			if (body != null) {
 				try {
-					body.interpretSafe(cx, scope);
+					body.interpretSafe(scope);
 				} catch (BreakExit exit) {
 					if (exit.stop == this) {
 						break;
@@ -46,6 +45,6 @@ public void interpret(Context cx, Scope scope) {
 				}
 			}
 		}
-		while (cx.asBoolean(scope, condition));
+		while (scope.asBoolean(condition));
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstEmptyBlock.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstEmptyBlock.java
index 3c282b4..01e7d18 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstEmptyBlock.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstEmptyBlock.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 import dev.latvian.apps.ichor.exit.ReturnExit;
@@ -19,7 +18,7 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		if (forceReturn) {
 			throw ReturnExit.DEFAULT_RETURN;
 		}
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstExport.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstExport.java
index 36b1d8a..2c8adcd 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstExport.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstExport.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 
@@ -18,7 +17,7 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		// TODO: Implement
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstExpressionStatement.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstExpressionStatement.java
index 4575858..b20e8ff 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstExpressionStatement.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstExpressionStatement.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -19,8 +18,8 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
-		cx.eval(scope, expression);
+	public void interpret(Scope scope) {
+		scope.eval(expression);
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstFor.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstFor.java
index 7c42656..7c693ce 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstFor.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstFor.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -51,13 +50,13 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		var s = scope.push();
 
-		for (initializer.interpretSafe(cx, scope); condition == null || cx.asBoolean(scope, condition); increment.interpretSafe(cx, scope)) {
+		for (initializer.interpretSafe(scope); condition == null || scope.asBoolean(condition); increment.interpretSafe(scope)) {
 			try {
 				if (body != null) {
-					body.interpretSafe(cx, s);
+					body.interpretSafe(s);
 				}
 			} catch (BreakExit exit) {
 				if (exit.stop == this) {
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstForIn.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstForIn.java
index 053feac..aa5d8a6 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstForIn.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstForIn.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.util.IchorUtils;
 import org.jetbrains.annotations.Nullable;
@@ -17,7 +16,7 @@ protected String appendKeyword() {
 
 	@Override
 	@Nullable
-	protected Iterator<?> getIterable(Context cx, Scope scope, Object self) {
+	protected Iterator<?> getIterable(Scope scope, Object self) {
 		if (self instanceof Collection<?> c) {
 			var keys = new Object[c.size()];
 
@@ -37,8 +36,8 @@ protected Iterator<?> getIterable(Context cx, Scope scope, Object self) {
 
 			return keys.iterator();
 		} else {
-			var p = cx.getPrototype(scope, self);
-			return IchorUtils.iteratorOf(p.keys(cx, scope, p.cast(self)));
+			var p = scope.getPrototype(self);
+			return IchorUtils.iteratorOf(p.keys(scope, p.cast(self)));
 		}
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstForOf.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstForOf.java
index 1f784f6..46a5c99 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstForOf.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstForOf.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -50,17 +49,17 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
-		var self = cx.eval(scope, from);
-		var itr = getIterable(cx, scope, self);
+	public void interpret(Scope scope) {
+		var self = scope.eval(from);
+		var itr = getIterable(scope, self);
 
 		while (itr != null && itr.hasNext()) {
 			var it = itr.next();
 
 			try {
 				var s = scope.push();
-				declaration.declare(cx, s, assignToken.flags, it);
-				body.interpretSafe(cx, s);
+				declaration.declare(s, assignToken.flags, it);
+				body.interpretSafe(s);
 			} catch (BreakExit exit) {
 				if (exit.stop == this) {
 					break;
@@ -76,15 +75,15 @@ public void interpret(Context cx, Scope scope) {
 	}
 
 	@Nullable
-	protected Iterator<?> getIterable(Context cx, Scope scope, Object self) {
+	protected Iterator<?> getIterable(Scope scope, Object self) {
 		var itr = IchorUtils.iteratorOf(self);
 
 		if (itr != null) {
 			return itr;
 		}
 
-		var p = cx.getPrototype(scope, self);
-		return IchorUtils.iteratorOf(p.values(cx, scope, p.cast(self)));
+		var p = scope.getPrototype(self);
+		return IchorUtils.iteratorOf(p.values(scope, p.cast(self)));
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstFunctionDeclareStatement.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstFunctionDeclareStatement.java
index a8242ea..2e58557 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstFunctionDeclareStatement.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstFunctionDeclareStatement.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -16,8 +15,8 @@ public AstFunctionDeclareStatement(AstFunction function) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
-		scope.addImmutable(function.functionName, cx.eval(scope, function));
+	public void interpret(Scope scope) {
+		scope.addImmutable(function.functionName, scope.eval(function));
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstIf.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstIf.java
index d19e89e..d6a3d57 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstIf.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstIf.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -42,14 +41,14 @@ public boolean handle(ExitType type) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		try {
-			if (cx.asBoolean(scope, condition)) {
+			if (scope.asBoolean(condition)) {
 				if (trueBody != null) {
-					trueBody.interpretSafe(cx, scope);
+					trueBody.interpretSafe(scope);
 				}
 			} else if (falseBody != null) {
-				falseBody.interpretSafe(cx, scope);
+				falseBody.interpretSafe(scope);
 			}
 		} catch (BreakExit exit) {
 			if (exit.stop != this) {
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstInterpretableGroup.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstInterpretableGroup.java
index 03118eb..20df980 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstInterpretableGroup.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstInterpretableGroup.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -32,9 +31,9 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		for (var statement : interpretable) {
-			statement.interpretSafe(cx, scope);
+			statement.interpretSafe(scope);
 		}
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstMultiDeclareStatement.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstMultiDeclareStatement.java
index f85ce59..444db0f 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstMultiDeclareStatement.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstMultiDeclareStatement.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -31,9 +30,9 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		for (var p : parts) {
-			p.declaration.declare(cx, scope, assignToken.flags, cx.eval(scope, p.value));
+			p.declaration.declare(scope, assignToken.flags, scope.eval(p.value));
 		}
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstReturn.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstReturn.java
index 4b7f14c..629fd76 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstReturn.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstReturn.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
@@ -21,8 +20,8 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
-		var result = cx.eval(scope, value);
+	public void interpret(Scope scope) {
+		var result = scope.eval(value);
 		throw result == Special.UNDEFINED ? ReturnExit.DEFAULT_RETURN : new ReturnExit(result);
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSingleDeclareStatement.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSingleDeclareStatement.java
index 1894163..b07617d 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSingleDeclareStatement.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSingleDeclareStatement.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -28,8 +27,8 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
-		declaration.declare(cx, scope, assignToken.flags, cx.eval(scope, value));
+	public void interpret(Scope scope) {
+		declaration.declare(scope, assignToken.flags, scope.eval(value));
 	}
 
 	@Override
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSuperStatement.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSuperStatement.java
index 3863d9c..bf1bb59 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSuperStatement.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSuperStatement.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.error.ScriptError;
 import dev.latvian.apps.ichor.util.ClassPrototype;
@@ -22,7 +21,7 @@ public String getStatementName() {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		if (scope.scopeThis instanceof ClassPrototype.Instance c) {
 			c.interpretConstructorSuper(arguments);
 		} else {
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSwitch.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSwitch.java
index 8b85fa4..102675d 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSwitch.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstSwitch.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -53,11 +52,11 @@ public boolean handle(ExitType type) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		for (AstCase c : cases) {
-			if (cx.equals(scope, expression, c.value, true)) {
+			if (scope.equals(expression, c.value, true)) {
 				try {
-					c.body.interpretSafe(cx, scope);
+					c.body.interpretSafe(scope);
 				} catch (BreakExit exit) {
 					if (exit.stop == this) {
 						return;
@@ -70,7 +69,7 @@ public void interpret(Context cx, Scope scope) {
 
 		if (defaultCase != null) {
 			try {
-				defaultCase.body.interpretSafe(cx, scope);
+				defaultCase.body.interpretSafe(scope);
 			} catch (BreakExit ignored) {
 			}
 		}
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstThisStatement.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstThisStatement.java
index f9d59c6..a5af3a4 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstThisStatement.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstThisStatement.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -40,7 +39,7 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		throw new InvalidCallError();
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstThrow.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstThrow.java
index 555e148..971590a 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstThrow.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstThrow.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -21,8 +20,8 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
-		var e = cx.eval(scope, exception);
+	public void interpret(Scope scope) {
+		var e = scope.eval(exception);
 
 		if (e instanceof Throwable t) {
 			throw new ScriptThrowError(t).pos(this);
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstTry.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstTry.java
index 2cb5d5f..1db789d 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstTry.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstTry.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -49,20 +48,20 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		try {
 			if (tryBlock != null) {
-				tryBlock.interpretSafe(cx, scope);
+				tryBlock.interpretSafe(scope);
 			}
 		} catch (Exception ex) {
 			if (catchBlock != null && catchBlock.body != null) {
 				var s = scope.push();
 				s.addMutable(catchBlock.name, ex);
-				catchBlock.body.interpretSafe(cx, s);
+				catchBlock.body.interpretSafe(s);
 			}
 		} finally {
 			if (finallyBlock != null) {
-				finallyBlock.interpretSafe(cx, scope);
+				finallyBlock.interpretSafe(scope);
 			}
 		}
 	}
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstWhile.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstWhile.java
index 21622dd..c5cbac8 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstWhile.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstWhile.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Interpretable;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
@@ -26,11 +25,11 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
-		while (cx.asBoolean(scope, condition)) {
+	public void interpret(Scope scope) {
+		while (scope.asBoolean(condition)) {
 			if (body != null) {
 				try {
-					body.interpretSafe(cx, scope);
+					body.interpretSafe(scope);
 				} catch (BreakExit exit) {
 					if (exit.stop == this) {
 						break;
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstYield.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstYield.java
index 1f2124a..0fb7a62 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/AstYield.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/AstYield.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Parser;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -27,7 +26,7 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void interpret(Context cx, Scope scope) {
+	public void interpret(Scope scope) {
 		throw new WIPFeatureError();
 	}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/AstDeclaration.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/AstDeclaration.java
index d251624..78ab98a 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/AstDeclaration.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/AstDeclaration.java
@@ -1,11 +1,10 @@
 package dev.latvian.apps.ichor.ast.statement.decl;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AppendableAst;
 
 public interface AstDeclaration extends AppendableAst {
 	AstDeclaration[] EMPTY = new AstDeclaration[0];
 
-	void declare(Context cx, Scope scope, byte flags, Object of);
+	void declare(Scope scope, byte flags, Object of);
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredArray.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredArray.java
index e76f4e0..2b5214a 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredArray.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredArray.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement.decl;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 
@@ -35,19 +34,19 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void declare(Context cx, Scope scope, byte flags, Object value) {
-		var p = cx.getPrototype(scope, value);
+	public void declare(Scope scope, byte flags, Object value) {
+		var p = scope.getPrototype(value);
 
 		for (var decl : parts) {
-			decl.declare(cx, scope, flags, value);
+			decl.declare(scope, flags, value);
 		}
 
 		if (!rest.isEmpty()) {
-			int len = value instanceof Collection<?> c ? c.size() : p.getLength(cx, scope, value);
+			int len = value instanceof Collection<?> c ? c.size() : p.getLength(scope, value);
 			var restArr = new ArrayList<>();
 
 			for (int i = restIndex; i < len; i++) {
-				restArr.add(p.getLocal(cx, scope, p.cast(value), i));
+				restArr.add(p.getLocal(scope, p.cast(value), i));
 			}
 
 			scope.add(rest, restArr, flags);
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredArrayName.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredArrayName.java
index 0b4afc4..a40b211 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredArrayName.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredArrayName.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement.decl;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -13,9 +12,9 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void declare(Context cx, Scope scope, byte flags, Object value) {
-		var p = cx.getPrototype(scope, value);
-		var v = p.getLocal(cx, scope, p.cast(value), index);
+	public void declare(Scope scope, byte flags, Object value) {
+		var p = scope.getPrototype(value);
+		var v = p.getLocal(scope, p.cast(value), index);
 
 		if (v != Special.NOT_FOUND) {
 			scope.add(name, v, flags);
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredObject.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredObject.java
index 4af235a..93c24d9 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredObject.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredObject.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement.decl;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 
@@ -36,16 +35,16 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void declare(Context cx, Scope scope, byte flags, Object value) {
-		var p = cx.getPrototype(scope, value);
+	public void declare(Scope scope, byte flags, Object value) {
+		var p = scope.getPrototype(value);
 
 		for (var decl : parts) {
-			decl.declare(cx, scope, flags, value);
+			decl.declare(scope, flags, value);
 		}
 
 		if (!rest.isEmpty()) {
 			// TODO: special case Map for efficiency
-			var keys = p.keys(cx, scope, p.cast(value));
+			var keys = p.keys(scope, p.cast(value));
 
 			if (keys != null) {
 				var restObj = new LinkedHashMap<String, Object>(keys.size() - ignoredRest.size());
@@ -54,7 +53,7 @@ public void declare(Context cx, Scope scope, byte flags, Object value) {
 					var ks = k.toString();
 
 					if (!ignoredRest.contains(ks)) {
-						restObj.put(ks, p.getInternal(cx, scope, value, ks));
+						restObj.put(ks, p.getInternal(scope, value, ks));
 					}
 				}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredObjectName.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredObjectName.java
index 8ae2c2a..8a5f6fa 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredObjectName.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/DestructuredObjectName.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement.decl;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -28,9 +27,9 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void declare(Context cx, Scope scope, byte flags, Object value) {
-		var p = cx.getPrototype(scope, value);
-		var v = p.getInternal(cx, scope, value, name);
+	public void declare(Scope scope, byte flags, Object value) {
+		var p = scope.getPrototype(value);
+		var v = p.getInternal(scope, value, name);
 
 		if (v != Special.NOT_FOUND) {
 			scope.add(rename, v, flags);
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/NameDeclaration.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/NameDeclaration.java
index 8ad09e0..905fb4e 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/NameDeclaration.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/NameDeclaration.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement.decl;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 import dev.latvian.apps.ichor.ast.expression.AstType;
@@ -30,9 +29,9 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void declare(Context cx, Scope scope, byte flags, Object value) {
+	public void declare(Scope scope, byte flags, Object value) {
 		if (type != null) {
-			scope.add(name, type.cast(cx, scope, value), flags);
+			scope.add(name, type.cast(scope, value), flags);
 		} else {
 			scope.add(name, value, flags);
 		}
diff --git a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/NestedDestructuredPart.java b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/NestedDestructuredPart.java
index f2ca2af..7c090d3 100644
--- a/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/NestedDestructuredPart.java
+++ b/src/main/java/dev/latvian/apps/ichor/ast/statement/decl/NestedDestructuredPart.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.ast.statement.decl;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -23,12 +22,12 @@ public void append(AstStringBuilder builder) {
 	}
 
 	@Override
-	public void declare(Context cx, Scope scope, byte flags, Object value) {
-		var p = cx.getPrototype(scope, value);
-		var o = p.getInternal(cx, scope, value, name);
+	public void declare(Scope scope, byte flags, Object value) {
+		var p = scope.getPrototype(value);
+		var o = p.getInternal(scope, value, name);
 
 		if (o != Special.NOT_FOUND) {
-			part.declare(cx, scope, flags, o);
+			part.declare(scope, flags, o);
 		} else {
 			throw new NamedMemberNotFoundError(name, p, value);
 		}
diff --git a/src/main/java/dev/latvian/apps/ichor/java/AnnotatedElementPrototype.java b/src/main/java/dev/latvian/apps/ichor/java/AnnotatedElementPrototype.java
index 57a5409..4b1ea14 100644
--- a/src/main/java/dev/latvian/apps/ichor/java/AnnotatedElementPrototype.java
+++ b/src/main/java/dev/latvian/apps/ichor/java/AnnotatedElementPrototype.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.java;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.util.Functions;
@@ -10,18 +9,18 @@
 
 @SuppressWarnings("unchecked")
 public class AnnotatedElementPrototype extends Prototype<AnnotatedElement> {
-	private static final Functions.Bound<AnnotatedElement> GET_ANNOTATION = (cx, scope, cl, args) -> cl.getAnnotation(cx.asClass(scope, args[0]));
-	private static final Functions.Bound<AnnotatedElement> GET_DECLARED_ANNOTATION = (cx, scope, cl, args) -> cl.getDeclaredAnnotation(cx.asClass(scope, args[0]));
-	private static final Functions.Bound<AnnotatedElement> GET_ANNOTATIONS_BY_TYPE = (cx, scope, cl, args) -> cl.getAnnotationsByType(cx.asClass(scope, args[0]));
-	private static final Functions.Bound<AnnotatedElement> GET_DECLARED_ANNOTATIONS_BY_TYPE = (cx, scope, cl, args) -> cl.getDeclaredAnnotationsByType(cx.asClass(scope, args[0]));
+	private static final Functions.Bound<AnnotatedElement> GET_ANNOTATION = (scope, cl, args) -> cl.getAnnotation(scope.asClass(args[0]));
+	private static final Functions.Bound<AnnotatedElement> GET_DECLARED_ANNOTATION = (scope, cl, args) -> cl.getDeclaredAnnotation(scope.asClass(args[0]));
+	private static final Functions.Bound<AnnotatedElement> GET_ANNOTATIONS_BY_TYPE = (scope, cl, args) -> cl.getAnnotationsByType(scope.asClass(args[0]));
+	private static final Functions.Bound<AnnotatedElement> GET_DECLARED_ANNOTATIONS_BY_TYPE = (scope, cl, args) -> cl.getDeclaredAnnotationsByType(scope.asClass(args[0]));
 
-	public AnnotatedElementPrototype(Context cx) {
+	public AnnotatedElementPrototype(Scope cx) {
 		super(cx, AnnotatedElement.class);
 	}
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, AnnotatedElement self, String name) {
+	public Object getLocal(Scope scope, AnnotatedElement self, String name) {
 		return switch (name) {
 			case "annotations" -> self.getAnnotations();
 			case "declaredAnnotations" -> self.getDeclaredAnnotations();
@@ -29,7 +28,7 @@ public Object getLocal(Context cx, Scope scope, AnnotatedElement self, String na
 			case "getDeclaredAnnotation" -> GET_DECLARED_ANNOTATION.with(self);
 			case "getAnnotationsByType" -> GET_ANNOTATIONS_BY_TYPE.with(self);
 			case "getDeclaredAnnotationsByType" -> GET_DECLARED_ANNOTATIONS_BY_TYPE.with(self);
-			default -> super.getLocal(cx, scope, self, name);
+			default -> super.getLocal(scope, self, name);
 		};
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/java/BooleanPrototype.java b/src/main/java/dev/latvian/apps/ichor/java/BooleanPrototype.java
index 7c68ed8..1ede255 100644
--- a/src/main/java/dev/latvian/apps/ichor/java/BooleanPrototype.java
+++ b/src/main/java/dev/latvian/apps/ichor/java/BooleanPrototype.java
@@ -1,27 +1,26 @@
 package dev.latvian.apps.ichor.java;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.util.IchorUtils;
 
 public class BooleanPrototype extends Prototype<Boolean> {
-	public BooleanPrototype(Context cx) {
+	public BooleanPrototype(Scope cx) {
 		super(cx, Boolean.class);
 	}
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
-		return args.length == 0 ? Boolean.FALSE : cx.asBoolean(scope, args[0]);
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
+		return args.length == 0 ? Boolean.FALSE : scope.asBoolean(args[0]);
 	}
 
 	@Override
-	public Number asNumber(Context cx, Scope scope, Boolean self) {
+	public Number asNumber(Scope scope, Boolean self) {
 		return self ? IchorUtils.ONE : IchorUtils.ZERO;
 	}
 
 	@Override
-	public Boolean asBoolean(Context cx, Scope scope, Boolean self) {
+	public Boolean asBoolean(Scope scope, Boolean self) {
 		return self;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/java/JavaClassPrototype.java b/src/main/java/dev/latvian/apps/ichor/java/JavaClassPrototype.java
index a98f994..cc88c10 100644
--- a/src/main/java/dev/latvian/apps/ichor/java/JavaClassPrototype.java
+++ b/src/main/java/dev/latvian/apps/ichor/java/JavaClassPrototype.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.java;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.util.Functions;
@@ -9,10 +8,10 @@
 import java.lang.reflect.AnnotatedElement;
 
 public class JavaClassPrototype extends Prototype<Class<?>> {
-	private static final Functions.Bound<Class<?>> IS_INSTANCE = (cx, scope, cl, args) -> cl.isInstance(args[0]);
-	private static final Functions.Bound<Class<?>> IS_ASSIGNABLE_FROM = (cx, scope, cl, args) -> cl.isAssignableFrom(cx.asClass(scope, args[0]));
+	private static final Functions.Bound<Class<?>> IS_INSTANCE = (scope, cl, args) -> cl.isInstance(args[0]);
+	private static final Functions.Bound<Class<?>> IS_ASSIGNABLE_FROM = (scope, cl, args) -> cl.isAssignableFrom(scope.asClass(args[0]));
 
-	public JavaClassPrototype(Context cx) {
+	public JavaClassPrototype(Scope cx) {
 		super(cx, "JavaClass", Class.class);
 	}
 
@@ -22,12 +21,12 @@ protected void initMembers() {
 
 	@Override
 	protected void initParents() {
-		parent(context.getClassPrototype(AnnotatedElement.class));
+		parent(initialScope.getClassPrototype(AnnotatedElement.class));
 	}
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, Class<?> self, String name) {
+	public Object getLocal(Scope scope, Class<?> self, String name) {
 		return switch (name) {
 			case "name" -> self.getName();
 			case "superclass" -> self.getSuperclass();
@@ -50,12 +49,12 @@ public Object getLocal(Context cx, Scope scope, Class<?> self, String name) {
 			case "enclosingClass" -> self.getEnclosingClass();
 			case "isInstance" -> IS_INSTANCE.with(self);
 			case "isAssignableFrom" -> IS_ASSIGNABLE_FROM.with(self);
-			default -> super.getLocal(cx, scope, self, name);
+			default -> super.getLocal(scope, self, name);
 		};
 	}
 
 	@Override
-	public boolean asString(Context cx, Scope scope, Class<?> self, StringBuilder builder, boolean escape) {
+	public boolean asString(Scope scope, Class<?> self, StringBuilder builder, boolean escape) {
 		builder.append(self.getName());
 		return true;
 	}
diff --git a/src/main/java/dev/latvian/apps/ichor/java/JavaMembers.java b/src/main/java/dev/latvian/apps/ichor/java/JavaMembers.java
index 81f4440..8d180cc 100644
--- a/src/main/java/dev/latvian/apps/ichor/java/JavaMembers.java
+++ b/src/main/java/dev/latvian/apps/ichor/java/JavaMembers.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.java;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.expression.AstCall;
 import dev.latvian.apps.ichor.error.InternalScriptError;
@@ -94,7 +93,7 @@ public void addMethod(Method m, Signature signature, Map<String, JavaMembers> ot
 		}
 	}
 
-	public Object call(Context cx, Scope scope, Object[] args, @Nullable Object self) {
+	public Object call(Scope scope, Object[] args, @Nullable Object self) {
 		if (methods == null) {
 			throw new AstCall.CallError(this, this, prototype);
 		}
@@ -110,7 +109,7 @@ public Object call(Context cx, Scope scope, Object[] args, @Nullable Object self
 						var args1 = new Object[m.signature.types.length];
 
 						for (int i = 0; i < args1.length; i++) {
-							args1[i] = cx.as(scope, args[i], m.signature.types[i]);
+							args1[i] = scope.as(args[i], m.signature.types[i]);
 						}
 
 						return m.method.invoke(self, args1);
diff --git a/src/main/java/dev/latvian/apps/ichor/java/LocalJavaMembers.java b/src/main/java/dev/latvian/apps/ichor/java/LocalJavaMembers.java
index 87cea58..c3e14eb 100644
--- a/src/main/java/dev/latvian/apps/ichor/java/LocalJavaMembers.java
+++ b/src/main/java/dev/latvian/apps/ichor/java/LocalJavaMembers.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.java;
 
 import dev.latvian.apps.ichor.CallableTypeAdapter;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.error.InternalScriptError;
@@ -10,15 +9,10 @@
 import org.jetbrains.annotations.Nullable;
 
 public record LocalJavaMembers(JavaMembers members) implements PrototypeProperty {
-	public record CallWrapper(Context evalContext, Scope evalScope, Object self, JavaMembers members) implements CallableTypeAdapter {
+	public record CallWrapper(Scope evalScope, Object self, JavaMembers members) implements CallableTypeAdapter {
 		@Override
-		public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
-			return members.call(cx, scope, args, self);
-		}
-
-		@Override
-		public Context getEvalContext() {
-			return evalContext;
+		public Object call(Scope scope, Object[] args, boolean hasNew) {
+			return members.call(scope, args, self);
 		}
 
 		@Override
@@ -38,7 +32,7 @@ public int hashCode() {
 	}
 
 	@Override
-	public Object get(Context cx, Scope scope, Object self) {
+	public Object get(Scope scope, Object self) {
 		try {
 			if (members.beanGet != null) {
 				return members.beanGet.invoke(self, Empty.OBJECTS);
@@ -52,22 +46,22 @@ public Object get(Context cx, Scope scope, Object self) {
 		}
 
 		if (members.methods != null) {
-			return new CallWrapper(cx, scope, self, members);
+			return new CallWrapper(scope, self, members);
 		}
 
 		return Special.NOT_FOUND;
 	}
 
 	@Override
-	public boolean set(Context cx, Scope scope, Object self, @Nullable Object value) {
+	public boolean set(Scope scope, Object self, @Nullable Object value) {
 		try {
 			if (members.beanSet != null) {
-				members.beanSet.invoke(self, cx.as(scope, value, members.beanSetType));
+				members.beanSet.invoke(self, scope.as(value, members.beanSetType));
 				return true;
 			}
 
 			if (members.field != null) {
-				members.field.set(self, cx.as(scope, value, members.field.getType()));
+				members.field.set(self, scope.as(value, members.field.getType()));
 				return true;
 			}
 		} catch (Exception ex) {
diff --git a/src/main/java/dev/latvian/apps/ichor/java/StaticJavaMembers.java b/src/main/java/dev/latvian/apps/ichor/java/StaticJavaMembers.java
index fa29789..56f0790 100644
--- a/src/main/java/dev/latvian/apps/ichor/java/StaticJavaMembers.java
+++ b/src/main/java/dev/latvian/apps/ichor/java/StaticJavaMembers.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.java;
 
 import dev.latvian.apps.ichor.CallableTypeAdapter;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.error.InternalScriptError;
@@ -10,15 +9,10 @@
 import org.jetbrains.annotations.Nullable;
 
 public record StaticJavaMembers(JavaMembers members) implements PrototypeStaticProperty {
-	public record CallWrapper(Context evalContext, Scope evalScope, JavaMembers members) implements CallableTypeAdapter {
+	public record CallWrapper(Scope evalScope, JavaMembers members) implements CallableTypeAdapter {
 		@Override
-		public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
-			return members.call(cx, scope, args, null);
-		}
-
-		@Override
-		public Context getEvalContext() {
-			return evalContext;
+		public Object call(Scope scope, Object[] args, boolean hasNew) {
+			return members.call(scope, args, null);
 		}
 
 		@Override
@@ -38,7 +32,7 @@ public int hashCode() {
 	}
 
 	@Override
-	public Object get(Context cx, Scope scope) {
+	public Object get(Scope scope) {
 		try {
 			if (members.beanGet != null) {
 				return members.beanGet.invoke(null, Empty.OBJECTS);
@@ -52,22 +46,22 @@ public Object get(Context cx, Scope scope) {
 		}
 
 		if (members.methods != null) {
-			return new CallWrapper(cx, scope, members);
+			return new CallWrapper(scope, members);
 		}
 
 		return Special.NOT_FOUND;
 	}
 
 	@Override
-	public boolean set(Context cx, Scope scope, @Nullable Object value) {
+	public boolean set(Scope scope, @Nullable Object value) {
 		try {
 			if (members.beanSet != null) {
-				members.beanSet.invoke(null, cx.as(scope, value, members.beanSetType));
+				members.beanSet.invoke(null, scope.as(value, members.beanSetType));
 				return true;
 			}
 
 			if (members.field != null) {
-				members.field.set(null, cx.as(scope, value, members.field.getType()));
+				members.field.set(null, scope.as(value, members.field.getType()));
 				return true;
 			}
 		} catch (Exception ex) {
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/Prototype.java b/src/main/java/dev/latvian/apps/ichor/prototype/Prototype.java
index 893c9df..c6ec734 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/Prototype.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/Prototype.java
@@ -1,8 +1,6 @@
 package dev.latvian.apps.ichor.prototype;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
-import dev.latvian.apps.ichor.Remapper;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.annotation.Hidden;
@@ -69,7 +67,7 @@ public ClassLoadingError(Class<?> type, Throwable ex) {
 	}
 
 	private final String prototypeName;
-	public final Context context;
+	public final Scope initialScope;
 	public final Class<T> type;
 	private PrototypeConstructor constructor;
 	private Map<String, PrototypeProperty> localProperties;
@@ -80,19 +78,19 @@ public ClassLoadingError(Class<?> type, Throwable ex) {
 
 	@SuppressWarnings({"rawtypes", "unchecked"})
 
-	public Prototype(Context cx, String name, Class type) {
-		this.context = cx;
+	public Prototype(Scope initialScope, String name, Class type) {
+		this.initialScope = initialScope;
 		this.type = type;
 		this.prototypeName = name;
 	}
 
 	@SuppressWarnings("rawtypes")
-	public Prototype(Context cx, Class type) {
-		this(cx, type.getName(), type);
+	public Prototype(Scope initialScope, Class type) {
+		this(initialScope, type.getName(), type);
 	}
 
 	@Override
-	public Prototype<T> getPrototype(Context cx, Scope scope) {
+	public Prototype<T> getPrototype(Scope scope) {
 		return this;
 	}
 
@@ -129,8 +127,6 @@ protected void initMembers() {
 		var localMap = new HashMap<String, JavaMembers>();
 		var staticMap = new HashMap<String, JavaMembers>();
 
-		var remapper = context.getRemapper();
-
 		try {
 			var prefixes0 = new HashSet<String>(0);
 
@@ -152,7 +148,7 @@ protected void initMembers() {
 				}
 
 				var map = Modifier.isStatic(mod) ? staticMap : localMap;
-				var members = map.computeIfAbsent(getFieldName(prefixes, remapper, f), JavaMembers::new);
+				var members = map.computeIfAbsent(getFieldName(prefixes, f), JavaMembers::new);
 				members.addField(f);
 			}
 
@@ -169,7 +165,7 @@ protected void initMembers() {
 
 				var map = Modifier.isStatic(mod) ? staticMap : localMap;
 				var signature = Signature.of(m);
-				var members = map.computeIfAbsent(getMethodName(prefixes, remapper, m, signature), JavaMembers::new);
+				var members = map.computeIfAbsent(getMethodName(prefixes, m, signature), JavaMembers::new);
 				members.addMethod(m, signature, map);
 			}
 		} catch (Exception ex) {
@@ -195,44 +191,40 @@ protected void initMembers() {
 		}
 	}
 
-	private String getFieldName(String[] prefixes, @Nullable Remapper remapper, Field field) {
+	private String getFieldName(String[] prefixes, Field field) {
 		var r = field.getAnnotation(Remap.class);
 
 		if (r != null) {
 			return r.value();
 		}
 
-		return remapper != null ? remapper.getFieldName(context, field) : field.getName();
+		return field.getName();
 	}
 
-	private String getMethodName(String[] prefixes, @Nullable Remapper remapper, Method method, Signature signature) {
+	private String getMethodName(String[] prefixes, Method method, Signature signature) {
 		var r = method.getAnnotation(Remap.class);
 
 		if (r != null) {
 			return r.value();
 		}
 
-		return remapper != null ? remapper.getMethodName(context, method, signature) : method.getName();
+		return method.getName();
 	}
 
 	protected void initParents() {
-		if (context == null) {
-			return;
-		}
-
 		var p = new ArrayList<Prototype<?>>(1);
 		// var p1 = new IdentityHashMap<Class<?>, Prototype<?>>();
 
 		for (var i : type.getInterfaces()) {
 			if (i != Serializable.class && i != Cloneable.class && i != Comparable.class/* && !p1.containsKey(i)*/) {
-				p.add(context.getClassPrototype(i));
+				p.add(initialScope.getClassPrototype(i));
 			}
 		}
 
 		var s = type.getSuperclass();
 
 		if (s != null && s != Object.class) {
-			var proto = context.getClassPrototype(s);
+			var proto = initialScope.getClassPrototype(s);
 			p.add(proto);
 			// proto.unfold(p1);
 		}
@@ -352,11 +344,11 @@ public void typeAdapter(PrototypeTypeAdapter<T> typeAdapter, Class<?>... toTypes
 	// Constructor
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
 		initProperties();
 
 		if (constructor != null) {
-			return constructor.construct(cx, scope, args, hasNew);
+			return constructor.construct(scope, args, hasNew);
 		}
 
 		throw new ConstructorError(this);
@@ -365,29 +357,29 @@ public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
 	// Internal getter methods
 
 	@Nullable
-	public Object getInternal(Context cx, Scope scope, Object self, String name) {
-		return self == this ? getStatic(cx, scope, name) : getLocal(cx, scope, cast(self), name);
+	public Object getInternal(Scope scope, Object self, String name) {
+		return self == this ? getStatic(scope, name) : getLocal(scope, cast(self), name);
 	}
 
-	public int getLength(Context cx, Scope scope, Object self) {
-		var o = getInternal(cx, scope, self, "length");
-		return o == Special.NOT_FOUND ? -1 : cx.asInt(scope, o);
+	public int getLength(Scope scope, Object self) {
+		var o = getInternal(scope, self, "length");
+		return o == Special.NOT_FOUND ? -1 : scope.asInt(o);
 	}
 
 	// Static Named
 
 	@Nullable
-	public Object getStatic(Context cx, Scope scope, String name) {
+	public Object getStatic(Scope scope, String name) {
 		initProperties();
 
 		var m = staticProperties.get(name);
 
 		if (m != null) {
-			return m.get(cx, scope);
+			return m.get(scope);
 		}
 
 		for (var p : getParents()) {
-			var r = p.getStatic(cx, scope, name);
+			var r = p.getStatic(scope, name);
 
 			if (r != Special.NOT_FOUND) {
 				return r;
@@ -397,17 +389,17 @@ public Object getStatic(Context cx, Scope scope, String name) {
 		return name.equals("class") ? type : Special.NOT_FOUND;
 	}
 
-	public boolean setStatic(Context cx, Scope scope, String name, @Nullable Object value) {
+	public boolean setStatic(Scope scope, String name, @Nullable Object value) {
 		initProperties();
 
 		var m = staticProperties.get(name);
 
 		if (m != null) {
-			return m.set(cx, scope, value);
+			return m.set(scope, value);
 		}
 
 		for (var p : getParents()) {
-			if (p.setStatic(cx, scope, name, value)) {
+			if (p.setStatic(scope, name, value)) {
 				return true;
 			}
 		}
@@ -418,17 +410,17 @@ public boolean setStatic(Context cx, Scope scope, String name, @Nullable Object
 	// Local Named
 
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, T self, String name) {
+	public Object getLocal(Scope scope, T self, String name) {
 		initProperties();
 
 		var m = localProperties.get(name);
 
 		if (m != null) {
-			return m.get(cx, scope, self);
+			return m.get(scope, self);
 		}
 
 		for (var p : getParents()) {
-			var r = p.getLocal(cx, scope, cast(self), name);
+			var r = p.getLocal(scope, cast(self), name);
 
 			if (r != Special.NOT_FOUND) {
 				return r;
@@ -438,17 +430,17 @@ public Object getLocal(Context cx, Scope scope, T self, String name) {
 		return name.equals("class") ? self.getClass() : Special.NOT_FOUND;
 	}
 
-	public boolean setLocal(Context cx, Scope scope, T self, String name, @Nullable Object value) {
+	public boolean setLocal(Scope scope, T self, String name, @Nullable Object value) {
 		initProperties();
 
 		var m = localProperties.get(name);
 
 		if (m != null) {
-			return m.set(cx, scope, self, value);
+			return m.set(scope, self, value);
 		}
 
 		for (var p : getParents()) {
-			if (p.setLocal(cx, scope, cast(self), name, value)) {
+			if (p.setLocal(scope, cast(self), name, value)) {
 				return true;
 			}
 		}
@@ -456,9 +448,9 @@ public boolean setLocal(Context cx, Scope scope, T self, String name, @Nullable
 		return false;
 	}
 
-	public boolean deleteLocal(Context cx, Scope scope, T self, String name) {
+	public boolean deleteLocal(Scope scope, T self, String name) {
 		for (var p : getParents()) {
-			if (p.deleteLocal(cx, scope, cast(self), name)) {
+			if (p.deleteLocal(scope, cast(self), name)) {
 				return true;
 			}
 		}
@@ -469,9 +461,9 @@ public boolean deleteLocal(Context cx, Scope scope, T self, String name) {
 	// Local Indexed
 
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, T self, int index) {
+	public Object getLocal(Scope scope, T self, int index) {
 		for (var p : getParents()) {
-			var r = p.getLocal(cx, scope, cast(self), index);
+			var r = p.getLocal(scope, cast(self), index);
 
 			if (r != Special.NOT_FOUND) {
 				return r;
@@ -481,9 +473,9 @@ public Object getLocal(Context cx, Scope scope, T self, int index) {
 		return Special.NOT_FOUND;
 	}
 
-	public boolean setLocal(Context cx, Scope scope, T self, int index, @Nullable Object value) {
+	public boolean setLocal(Scope scope, T self, int index, @Nullable Object value) {
 		for (var p : getParents()) {
-			if (p.setLocal(cx, scope, cast(self), index, value)) {
+			if (p.setLocal(scope, cast(self), index, value)) {
 				return true;
 			}
 		}
@@ -491,9 +483,9 @@ public boolean setLocal(Context cx, Scope scope, T self, int index, @Nullable Ob
 		return false;
 	}
 
-	public boolean deleteLocal(Context cx, Scope scope, T self, int index) {
+	public boolean deleteLocal(Scope scope, T self, int index) {
 		for (var p : getParents()) {
-			if (p.deleteLocal(cx, scope, cast(self), index)) {
+			if (p.deleteLocal(scope, cast(self), index)) {
 				return true;
 			}
 		}
@@ -504,9 +496,9 @@ public boolean deleteLocal(Context cx, Scope scope, T self, int index) {
 	// Iterators
 
 	@Nullable
-	public Collection<?> keys(Context cx, Scope scope, T self) {
+	public Collection<?> keys(Scope scope, T self) {
 		for (var p : getParents()) {
-			var r = p.keys(cx, scope, cast(self));
+			var r = p.keys(scope, cast(self));
 
 			if (r != null) {
 				return r;
@@ -517,9 +509,9 @@ public Collection<?> keys(Context cx, Scope scope, T self) {
 	}
 
 	@Nullable
-	public Collection<?> values(Context cx, Scope scope, T self) {
+	public Collection<?> values(Scope scope, T self) {
 		for (var p : getParents()) {
-			var r = p.values(cx, scope, cast(self));
+			var r = p.values(scope, cast(self));
 
 			if (r != null) {
 				return r;
@@ -530,9 +522,9 @@ public Collection<?> values(Context cx, Scope scope, T self) {
 	}
 
 	@Nullable
-	public Collection<?> entries(Context cx, Scope scope, T self) {
+	public Collection<?> entries(Scope scope, T self) {
 		for (var p : getParents()) {
-			var r = p.entries(cx, scope, cast(self));
+			var r = p.entries(scope, cast(self));
 
 			if (r != null) {
 				return r;
@@ -544,9 +536,9 @@ public Collection<?> entries(Context cx, Scope scope, T self) {
 
 	// Conversions
 
-	public boolean asString(Context cx, Scope scope, T self, StringBuilder builder, boolean escape) {
+	public boolean asString(Scope scope, T self, StringBuilder builder, boolean escape) {
 		for (var p : getParents()) {
-			if (p.asString(cx, scope, cast(self), builder, escape)) {
+			if (p.asString(scope, cast(self), builder, escape)) {
 				return true;
 			}
 		}
@@ -555,9 +547,9 @@ public boolean asString(Context cx, Scope scope, T self, StringBuilder builder,
 	}
 
 	@Nullable
-	public Number asNumber(Context cx, Scope scope, T self) {
+	public Number asNumber(Scope scope, T self) {
 		for (var p : getParents()) {
-			var r = p.asNumber(cx, scope, cast(self));
+			var r = p.asNumber(scope, cast(self));
 
 			if (r != null) {
 				return r;
@@ -568,9 +560,9 @@ public Number asNumber(Context cx, Scope scope, T self) {
 	}
 
 	@Nullable
-	public Boolean asBoolean(Context cx, Scope scope, T self) {
+	public Boolean asBoolean(Scope scope, T self) {
 		for (var p : getParents()) {
-			var r = p.asBoolean(cx, scope, cast(self));
+			var r = p.asBoolean(scope, cast(self));
 
 			if (r != null) {
 				return r;
@@ -581,12 +573,12 @@ public Boolean asBoolean(Context cx, Scope scope, T self) {
 	}
 
 	@Nullable
-	public Object adapt(Context cx, Scope scope, T self, @Nullable Class<?> toType) {
+	public Object adapt(Scope scope, T self, @Nullable Class<?> toType) {
 		if (typeAdapters != null) {
 			var a = typeAdapters.get(toType);
 
 			if (a != null) {
-				var r = a.adapt(cx, scope, self, toType);
+				var r = a.adapt(scope, self, toType);
 
 				if (r != Special.NOT_FOUND) {
 					return r;
@@ -595,7 +587,7 @@ public Object adapt(Context cx, Scope scope, T self, @Nullable Class<?> toType)
 		}
 
 		for (var p : getParents()) {
-			var r = p.adapt(cx, scope, cast(self), toType);
+			var r = p.adapt(scope, cast(self), toType);
 
 			if (r != Special.NOT_FOUND) {
 				return r;
@@ -607,12 +599,12 @@ public Object adapt(Context cx, Scope scope, T self, @Nullable Class<?> toType)
 
 	// Equality
 
-	public boolean equals(Context cx, Scope scope, T left, Object right, boolean shallow) {
+	public boolean equals(Scope scope, T left, Object right, boolean shallow) {
 		return shallow ? left == right : Objects.equals(left, right);
 	}
 
 	@SuppressWarnings({"unchecked", "rawtypes"})
-	public int compareTo(Context cx, Scope scope, T left, Object right) {
+	public int compareTo(Scope scope, T left, Object right) {
 		if (left instanceof Comparable l && right instanceof Comparable r) {
 			return l.compareTo(r);
 		}
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeConstant.java b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeConstant.java
index 542310b..f94b1b2 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeConstant.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeConstant.java
@@ -1,11 +1,10 @@
 package dev.latvian.apps.ichor.prototype;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 public record PrototypeConstant(Object value) implements PrototypeStaticProperty {
 	@Override
-	public Object get(Context cx, Scope scope) {
+	public Object get(Scope scope) {
 		return value;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeConstructor.java b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeConstructor.java
index 744127b..a49476b 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeConstructor.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeConstructor.java
@@ -1,9 +1,8 @@
 package dev.latvian.apps.ichor.prototype;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 @FunctionalInterface
 public interface PrototypeConstructor {
-	Object construct(Context cx, Scope scope, Object[] args, boolean hasNew);
+	Object construct(Scope scope, Object[] args, boolean hasNew);
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeFunction.java b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeFunction.java
index 5151c4f..ed861d8 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeFunction.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeFunction.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.prototype;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.error.ConstructorError;
 
@@ -9,19 +8,19 @@
 public interface PrototypeFunction extends PrototypeProperty {
 	record CallWrapper(Object self, Scope evalScope, PrototypeFunction function) implements Callable {
 		@Override
-		public Object call(Context cx, Scope callScope, Object[] args, boolean hasNew) {
+		public Object call(Scope callScope, Object[] args, boolean hasNew) {
 			if (hasNew) {
 				throw new ConstructorError(null);
 			}
 
-			return function.call(cx, evalScope, self, args);
+			return function.call(evalScope, self, args);
 		}
 	}
 
-	Object call(Context cx, Scope scope, Object self, Object[] args);
+	Object call(Scope scope, Object self, Object[] args);
 
 	@Override
-	default Object get(Context cx, Scope scope, Object self) {
+	default Object get(Scope scope, Object self) {
 		return new CallWrapper(self, scope, this);
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeProperty.java b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeProperty.java
index cf15357..e1d2f1d 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeProperty.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeProperty.java
@@ -1,14 +1,13 @@
 package dev.latvian.apps.ichor.prototype;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import org.jetbrains.annotations.Nullable;
 
 @FunctionalInterface
 public interface PrototypeProperty {
-	Object get(Context cx, Scope scope, Object self);
+	Object get(Scope scope, Object self);
 
-	default boolean set(Context cx, Scope scope, Object self, @Nullable Object value) {
+	default boolean set(Scope scope, Object self, @Nullable Object value) {
 		return false;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeStaticFunction.java b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeStaticFunction.java
index b19204d..6163d0f 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeStaticFunction.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeStaticFunction.java
@@ -1,20 +1,19 @@
 package dev.latvian.apps.ichor.prototype;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 @FunctionalInterface
 public interface PrototypeStaticFunction extends PrototypeStaticProperty, Callable {
-	Object call(Context cx, Scope scope, Object[] args);
+	Object call(Scope scope, Object[] args);
 
 	@Override
-	default Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
-		return call(cx, scope, args);
+	default Object call(Scope scope, Object[] args, boolean hasNew) {
+		return call(scope, args);
 	}
 
 	@Override
-	default Object get(Context cx, Scope scope) {
+	default Object get(Scope scope) {
 		return this;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeStaticProperty.java b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeStaticProperty.java
index 174b006..93dd434 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeStaticProperty.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeStaticProperty.java
@@ -1,14 +1,13 @@
 package dev.latvian.apps.ichor.prototype;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import org.jetbrains.annotations.Nullable;
 
 @FunctionalInterface
 public interface PrototypeStaticProperty {
-	Object get(Context cx, Scope scope);
+	Object get(Scope scope);
 
-	default boolean set(Context cx, Scope scope, @Nullable Object value) {
+	default boolean set(Scope scope, @Nullable Object value) {
 		return false;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeSupplier.java b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeSupplier.java
index 1633999..0cda046 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeSupplier.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeSupplier.java
@@ -1,9 +1,8 @@
 package dev.latvian.apps.ichor.prototype;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 
 @FunctionalInterface
 public interface PrototypeSupplier {
-	Prototype<?> getPrototype(Context cx, Scope scope);
+	Prototype<?> getPrototype(Scope scope);
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeTypeAdapter.java b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeTypeAdapter.java
index 44f9d97..76285a2 100644
--- a/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeTypeAdapter.java
+++ b/src/main/java/dev/latvian/apps/ichor/prototype/PrototypeTypeAdapter.java
@@ -1,18 +1,17 @@
 package dev.latvian.apps.ichor.prototype;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 
 @FunctionalInterface
 public interface PrototypeTypeAdapter<T> {
-	Object adapt(Context cx, Scope scope, T self, Class<?> toType);
+	Object adapt(Scope scope, T self, Class<?> toType);
 
 	record Fallback<T>(PrototypeTypeAdapter<T> main, PrototypeTypeAdapter<T> fallback) implements PrototypeTypeAdapter<T> {
 		@Override
-		public Object adapt(Context cx, Scope scope, T self, Class<?> toType) {
-			var r = main.adapt(cx, scope, self, toType);
-			return r != Special.NOT_FOUND ? r : fallback.adapt(cx, scope, self, toType);
+		public Object adapt(Scope scope, T self, Class<?> toType) {
+			var r = main.adapt(scope, self, toType);
+			return r != Special.NOT_FOUND ? r : fallback.adapt(scope, self, toType);
 		}
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/token/TokenStream.java b/src/main/java/dev/latvian/apps/ichor/token/TokenStream.java
index 89d90af..e2aacfe 100644
--- a/src/main/java/dev/latvian/apps/ichor/token/TokenStream.java
+++ b/src/main/java/dev/latvian/apps/ichor/token/TokenStream.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.token;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.error.TokenStreamError;
 import dev.latvian.apps.ichor.exit.EndOfFileExit;
 import dev.latvian.apps.ichor.util.IchorUtils;
@@ -30,19 +29,19 @@ public class TokenStream {
 	private final long timeout;
 	private long timeoutTime;
 
-	public TokenStream(Context cx, TokenSource source, String string) {
-		tokenSource = source;
-		input = string.toCharArray();
-		lines = string.split("\n");
-		pos = 0;
-		row = 1;
-		col = 1;
-		numberTokenCache = new HashMap<>();
-		nameTokenCache = new HashMap<>();
-		depth = new Stack<>();
-		currentDepth = null;
-		timeout = cx.getTokenStreamTimeout();
-		timeoutTime = 0L;
+	public TokenStream(long timeout, TokenSource source, String string) {
+		this.tokenSource = source;
+		this.input = string.toCharArray();
+		this.lines = string.split("\n");
+		this.pos = 0;
+		this.row = 1;
+		this.col = 1;
+		this.numberTokenCache = new HashMap<>();
+		this.nameTokenCache = new HashMap<>();
+		this.depth = new Stack<>();
+		this.currentDepth = null;
+		this.timeout = timeout;
+		this.timeoutTime = 0L;
 	}
 
 	private Token makeName(String s) {
diff --git a/src/main/java/dev/latvian/apps/ichor/type/ArrayJS.java b/src/main/java/dev/latvian/apps/ichor/type/ArrayJS.java
index 25210d8..7b7924d 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/ArrayJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/ArrayJS.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.type;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.util.Functions;
@@ -15,23 +14,23 @@ public class ArrayJS extends Prototype<ArrayJS> {
 	public static final Callable IS_ARRAY = Functions.WIP;
 	public static final Callable OF = Functions.WIP;
 
-	public ArrayJS(Context cx) {
+	public ArrayJS(Scope cx) {
 		super(cx, "Array", ArrayJS.class);
 	}
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
 		return args.length == 0 ? new ArrayList<>() : new ArrayList<>(Arrays.asList(args));
 	}
 
 	@Override
 	@Nullable
-	public Object getStatic(Context cx, Scope scope, String name) {
+	public Object getStatic(Scope scope, String name) {
 		return switch (name) {
 			case "from" -> FROM;
 			case "isArray" -> IS_ARRAY;
 			case "of" -> OF;
-			default -> super.getStatic(cx, scope, name);
+			default -> super.getStatic(scope, name);
 		};
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/type/CollectionJS.java b/src/main/java/dev/latvian/apps/ichor/type/CollectionJS.java
index 024122a..dd18b92 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/CollectionJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/CollectionJS.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.type;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import org.jetbrains.annotations.Nullable;
@@ -11,27 +10,27 @@
 
 @SuppressWarnings({"rawtypes"})
 public class CollectionJS extends Prototype<Collection> {
-	public CollectionJS(Context cx) {
+	public CollectionJS(Scope cx) {
 		super(cx, Collection.class);
 	}
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, Collection self, String name) {
+	public Object getLocal(Scope scope, Collection self, String name) {
 		return switch (name) {
 			case "length" -> self.size();
 			case "forEach" -> IterableJS.FOR_EACH.with(self);
-			default -> super.getLocal(cx, scope, self, name);
+			default -> super.getLocal(scope, self, name);
 		};
 	}
 
 	@Override
-	public int getLength(Context cx, Scope scope, Object self) {
+	public int getLength(Scope scope, Object self) {
 		return ((Collection) self).size();
 	}
 
 	@Override
-	public Collection<?> keys(Context cx, Scope scope, Collection self) {
+	public Collection<?> keys(Scope scope, Collection self) {
 		var keys = new Object[self.size()];
 
 		for (int i = 0; i < self.size(); i++) {
@@ -42,12 +41,12 @@ public Collection<?> keys(Context cx, Scope scope, Collection self) {
 	}
 
 	@Override
-	public Collection<?> values(Context cx, Scope scope, Collection self) {
+	public Collection<?> values(Scope scope, Collection self) {
 		return self;
 	}
 
 	@Override
-	public Collection<?> entries(Context cx, Scope scope, Collection self) {
+	public Collection<?> entries(Scope scope, Collection self) {
 		var entries = new Object[self.size()];
 
 		int i = 0;
diff --git a/src/main/java/dev/latvian/apps/ichor/type/IterableJS.java b/src/main/java/dev/latvian/apps/ichor/type/IterableJS.java
index 437f09e..448dd7a 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/IterableJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/IterableJS.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.type;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.util.Functions;
@@ -13,24 +12,24 @@
 
 @SuppressWarnings({"rawtypes"})
 public class IterableJS extends Prototype<Iterable> {
-	public static final Functions.Bound<Iterable> FOR_EACH = (cx, scope, self, args) -> {
+	public static final Functions.Bound<Iterable> FOR_EACH = (scope, self, args) -> {
 		var func = (Callable) args[0];
 		int i = 0;
 
 		for (var o : self) {
-			func.call(cx, scope, new Object[]{o, i, self}, false);
+			func.call(scope, new Object[]{o, i, self}, false);
 			i++;
 		}
 
 		return self;
 	};
 
-	public IterableJS(Context cx) {
+	public IterableJS(Scope cx) {
 		super(cx, Iterable.class);
 	}
 
 	@Override
-	public boolean asString(Context cx, Scope scope, Iterable self, StringBuilder builder, boolean escape) {
+	public boolean asString(Scope scope, Iterable self, StringBuilder builder, boolean escape) {
 		builder.append('[');
 
 		boolean first = true;
@@ -43,7 +42,7 @@ public boolean asString(Context cx, Scope scope, Iterable self, StringBuilder bu
 				builder.append(' ');
 			}
 
-			cx.asString(scope, o, builder, true);
+			scope.asString(o, builder, true);
 		}
 
 		builder.append(']');
@@ -52,7 +51,7 @@ public boolean asString(Context cx, Scope scope, Iterable self, StringBuilder bu
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, Iterable self, String name) {
+	public Object getLocal(Scope scope, Iterable self, String name) {
 		return switch (name) {
 			case "length" -> {
 				int i = 0;
@@ -62,12 +61,12 @@ public Object getLocal(Context cx, Scope scope, Iterable self, String name) {
 				yield i;
 			}
 			case "forEach" -> FOR_EACH.with(self);
-			default -> super.getLocal(cx, scope, self, name);
+			default -> super.getLocal(scope, self, name);
 		};
 	}
 
 	@Override
-	public Collection<?> keys(Context cx, Scope scope, Iterable self) {
+	public Collection<?> keys(Scope scope, Iterable self) {
 		var keys = new ArrayList<Integer>();
 
 		int i = 0;
@@ -80,7 +79,7 @@ public Collection<?> keys(Context cx, Scope scope, Iterable self) {
 	}
 
 	@Override
-	public Collection<?> values(Context cx, Scope scope, Iterable self) {
+	public Collection<?> values(Scope scope, Iterable self) {
 		var values = new ArrayList<>();
 
 		for (var o : self) {
@@ -91,7 +90,7 @@ public Collection<?> values(Context cx, Scope scope, Iterable self) {
 	}
 
 	@Override
-	public Collection<?> entries(Context cx, Scope scope, Iterable self) {
+	public Collection<?> entries(Scope scope, Iterable self) {
 		var entries = new ArrayList<List<Object>>();
 
 		int i = 0;
diff --git a/src/main/java/dev/latvian/apps/ichor/type/ListJS.java b/src/main/java/dev/latvian/apps/ichor/type/ListJS.java
index 1f04f78..0e62b49 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/ListJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/ListJS.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.type;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.util.Functions;
@@ -10,7 +9,7 @@
 
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class ListJS extends Prototype<List> {
-	public static final Functions.Bound<List> PUSH = (cx, scope, self, args) -> {
+	public static final Functions.Bound<List> PUSH = (scope, self, args) -> {
 		int len = self.size();
 
 		for (int i = 0; i < args.length; i++) {
@@ -20,10 +19,10 @@ public class ListJS extends Prototype<List> {
 		return self;
 	};
 
-	public static final Functions.Bound<List> POP = (cx, scope, self, args) -> self.remove(self.size() - 1);
-	public static final Functions.Bound<List> SHIFT = (cx, scope, self, args) -> self.remove(0);
+	public static final Functions.Bound<List> POP = (scope, self, args) -> self.remove(self.size() - 1);
+	public static final Functions.Bound<List> SHIFT = (scope, self, args) -> self.remove(0);
 
-	public static final Functions.Bound<List> UNSHIFT = (cx, scope, self, args) -> {
+	public static final Functions.Bound<List> UNSHIFT = (scope, self, args) -> {
 		for (int i = 0; i < args.length; i++) {
 			self.add(i, args[i]);
 		}
@@ -31,13 +30,13 @@ public class ListJS extends Prototype<List> {
 		return self;
 	};
 
-	public ListJS(Context cx) {
+	public ListJS(Scope cx) {
 		super(cx, List.class);
 	}
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, List self, String name) {
+	public Object getLocal(Scope scope, List self, String name) {
 		return switch (name) {
 			case "length" -> self.size();
 			case "push" -> PUSH.with(self);
@@ -45,29 +44,29 @@ public Object getLocal(Context cx, Scope scope, List self, String name) {
 			case "shift" -> SHIFT.with(self);
 			case "unshift" -> UNSHIFT.with(self);
 			case "forEach" -> IterableJS.FOR_EACH.with(self);
-			default -> super.getStatic(cx, scope, name);
+			default -> super.getStatic(scope, name);
 		};
 	}
 
 	@Override
-	public int getLength(Context cx, Scope scope, Object self) {
+	public int getLength(Scope scope, Object self) {
 		return ((List) self).size();
 	}
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, List self, int index) {
+	public Object getLocal(Scope scope, List self, int index) {
 		return self.get(index);
 	}
 
 	@Override
-	public boolean setLocal(Context cx, Scope scope, List self, int index, @Nullable Object value) {
+	public boolean setLocal(Scope scope, List self, int index, @Nullable Object value) {
 		self.set(index, cast(value));
 		return true;
 	}
 
 	@Override
-	public boolean deleteLocal(Context cx, Scope scope, List self, int index) {
+	public boolean deleteLocal(Scope scope, List self, int index) {
 		self.remove(index);
 		return true;
 	}
diff --git a/src/main/java/dev/latvian/apps/ichor/type/MapJS.java b/src/main/java/dev/latvian/apps/ichor/type/MapJS.java
index c1da170..ae8e381 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/MapJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/MapJS.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.type;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
@@ -14,17 +13,17 @@
 import java.util.Map;
 
 public class MapJS extends Prototype<Map<?, ?>> {
-	public MapJS(Context cx) {
+	public MapJS(Scope cx) {
 		super(cx, "Map", Map.class);
 	}
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
 		return new LinkedHashMap<>();
 	}
 
 	@Override
-	public boolean asString(Context cx, Scope scope, Map<?, ?> self, StringBuilder builder, boolean escape) {
+	public boolean asString(Scope scope, Map<?, ?> self, StringBuilder builder, boolean escape) {
 		builder.append('{');
 
 		boolean first = true;
@@ -40,7 +39,7 @@ public boolean asString(Context cx, Scope scope, Map<?, ?> self, StringBuilder b
 			AstStringBuilder.wrapKey(String.valueOf(entry.getKey()), builder);
 			builder.append(':');
 			builder.append(' ');
-			cx.asString(scope, entry.getValue(), builder, true);
+			scope.asString(entry.getValue(), builder, true);
 		}
 
 		builder.append('}');
@@ -49,44 +48,44 @@ public boolean asString(Context cx, Scope scope, Map<?, ?> self, StringBuilder b
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, Map<?, ?> self, String name) {
+	public Object getLocal(Scope scope, Map<?, ?> self, String name) {
 		var o = self.get(name);
 
 		if (o != null) {
 			return o == Special.NULL ? null : o;
 		}
 
-		return super.getLocal(cx, scope, self, name);
+		return super.getLocal(scope, self, name);
 	}
 
 	@Override
-	public int getLength(Context cx, Scope scope, Object self) {
+	public int getLength(Scope scope, Object self) {
 		return ((Map<?, ?>) self).size();
 	}
 
 	@Override
-	public boolean setLocal(Context cx, Scope scope, Map<?, ?> self, String name, @Nullable Object value) {
+	public boolean setLocal(Scope scope, Map<?, ?> self, String name, @Nullable Object value) {
 		self.put(cast(name), cast(value == null ? Special.NULL : value)); // FIXME: Casting
 		return true;
 	}
 
 	@Override
-	public boolean deleteLocal(Context cx, Scope scope, Map<?, ?> self, String name) {
+	public boolean deleteLocal(Scope scope, Map<?, ?> self, String name) {
 		return self.remove(name) != null;
 	}
 
 	@Override
-	public Collection<?> keys(Context cx, Scope scope, Map<?, ?> self) {
+	public Collection<?> keys(Scope scope, Map<?, ?> self) {
 		return self.keySet();
 	}
 
 	@Override
-	public Collection<?> values(Context cx, Scope scope, Map<?, ?> self) {
+	public Collection<?> values(Scope scope, Map<?, ?> self) {
 		return self.values();
 	}
 
 	@Override
-	public Collection<?> entries(Context cx, Scope scope, Map<?, ?> self) {
+	public Collection<?> entries(Scope scope, Map<?, ?> self) {
 		if (self.isEmpty()) {
 			return List.of();
 		} else if (self.size() == 1) {
diff --git a/src/main/java/dev/latvian/apps/ichor/type/MathJS.java b/src/main/java/dev/latvian/apps/ichor/type/MathJS.java
index 0e37107..8e23efe 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/MathJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/MathJS.java
@@ -1,19 +1,18 @@
 package dev.latvian.apps.ichor.type;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.util.IchorUtils;
 import org.jetbrains.annotations.Nullable;
 
 public class MathJS extends Prototype<MathJS> {
-	public MathJS(Context cx) {
+	public MathJS(Scope cx) {
 		super(cx, "Math", MathJS.class);
 	}
 
 	@Override
 	@Nullable
-	public Object getStatic(Context cx, Scope scope, String name) {
+	public Object getStatic(Scope scope, String name) {
 		return switch (name) {
 			case "PI" -> IchorUtils.PI;
 			case "E" -> IchorUtils.E;
@@ -58,7 +57,7 @@ public Object getStatic(Context cx, Scope scope, String name) {
 			case "log2" -> IchorUtils.LOG2;
 			case "fround" -> IchorUtils.FROUND;
 			case "clz32" -> IchorUtils.CLZ32;
-			default -> super.getStatic(cx, scope, name);
+			default -> super.getStatic(scope, name);
 		};
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/type/NumberJS.java b/src/main/java/dev/latvian/apps/ichor/type/NumberJS.java
index 5f8de1a..0d75af1 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/NumberJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/NumberJS.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.type;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 import dev.latvian.apps.ichor.prototype.Prototype;
@@ -14,49 +13,49 @@
 import java.util.List;
 
 public class NumberJS extends Prototype<Number> {
-	private static final Callable IS_FINITE = Functions.of1((cx, scope, arg) -> {
-		double d = cx.asDouble(scope, arg);
+	private static final Callable IS_FINITE = Functions.of1((scope, arg) -> {
+		double d = scope.asDouble(arg);
 		return !Double.isInfinite(d) && !Double.isNaN(d);
 	});
 
-	private static final Callable IS_NAN = Functions.of1((cx, scope, arg) -> Double.isNaN(cx.asDouble(scope, arg)));
+	private static final Callable IS_NAN = Functions.of1((scope, arg) -> Double.isNaN(scope.asDouble(arg)));
 
-	private static final Callable IS_INTEGER = Functions.of1((cx, scope, arg) -> {
-		double d = cx.asDouble(scope, arg);
+	private static final Callable IS_INTEGER = Functions.of1((scope, arg) -> {
+		double d = scope.asDouble(arg);
 		return !Double.isInfinite(d) && !Double.isNaN(d) && (Math.floor(d) == d);
 	});
 
-	private static final Callable IS_SAFE_INTEGER = Functions.of1((cx, scope, arg) -> {
-		double d = cx.asDouble(scope, arg);
+	private static final Callable IS_SAFE_INTEGER = Functions.of1((scope, arg) -> {
+		double d = scope.asDouble(arg);
 		return !Double.isInfinite(d) && !Double.isNaN(d) && (d <= IchorUtils.MAX_SAFE_INTEGER) && (d >= IchorUtils.MIN_SAFE_INTEGER) && (Math.floor(d) == d);
 	});
 
-	private static final Callable PARSE_FLOAT = Functions.of1(Context::asDouble);
-	private static final Callable PARSE_INT = Functions.of1(Context::asInt);
-
-	private static final Functions.Bound<Number> TO_FIXED = (cx, scope, num, args) -> AstStringBuilder.wrapNumber(num); // FIXME
-	private static final Functions.Bound<Number> TO_EXPONENTIAL = (cx, scope, num, args) -> AstStringBuilder.wrapNumber(num); // FIXME
-	private static final Functions.Bound<Number> TO_PRECISION = (cx, scope, num, args) -> AstStringBuilder.wrapNumber(num); // FIXME
-	private static final Functions.Bound<Number> TO_BYTE = (cx, scope, num, args) -> num.byteValue();
-	private static final Functions.Bound<Number> TO_SHORT = (cx, scope, num, args) -> num.shortValue();
-	private static final Functions.Bound<Number> TO_INT = (cx, scope, num, args) -> num.intValue();
-	private static final Functions.Bound<Number> TO_LONG = (cx, scope, num, args) -> num.longValue();
-	private static final Functions.Bound<Number> TO_FLOAT = (cx, scope, num, args) -> num.floatValue();
-	private static final Functions.Bound<Number> TO_DOUBLE = (cx, scope, num, args) -> num.doubleValue();
-	private static final Functions.Bound<Number> TO_CHAR = (cx, scope, num, args) -> (char) num.intValue();
-
-	public NumberJS(Context cx) {
+	private static final Callable PARSE_FLOAT = Functions.of1(Scope::asDouble);
+	private static final Callable PARSE_INT = Functions.of1(Scope::asInt);
+
+	private static final Functions.Bound<Number> TO_FIXED = (scope, num, args) -> AstStringBuilder.wrapNumber(num); // FIXME
+	private static final Functions.Bound<Number> TO_EXPONENTIAL = (scope, num, args) -> AstStringBuilder.wrapNumber(num); // FIXME
+	private static final Functions.Bound<Number> TO_PRECISION = (scope, num, args) -> AstStringBuilder.wrapNumber(num); // FIXME
+	private static final Functions.Bound<Number> TO_BYTE = (scope, num, args) -> num.byteValue();
+	private static final Functions.Bound<Number> TO_SHORT = (scope, num, args) -> num.shortValue();
+	private static final Functions.Bound<Number> TO_INT = (scope, num, args) -> num.intValue();
+	private static final Functions.Bound<Number> TO_LONG = (scope, num, args) -> num.longValue();
+	private static final Functions.Bound<Number> TO_FLOAT = (scope, num, args) -> num.floatValue();
+	private static final Functions.Bound<Number> TO_DOUBLE = (scope, num, args) -> num.doubleValue();
+	private static final Functions.Bound<Number> TO_CHAR = (scope, num, args) -> (char) num.intValue();
+
+	public NumberJS(Scope cx) {
 		super(cx, "Number", Number.class);
 	}
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
-		return args.length == 0 ? IchorUtils.NaN : cx.asNumber(scope, args[0]);
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
+		return args.length == 0 ? IchorUtils.NaN : scope.asNumber(args[0]);
 	}
 
 	@Override
 	@Nullable
-	public Object getStatic(Context cx, Scope scope, String name) {
+	public Object getStatic(Scope scope, String name) {
 		return switch (name) {
 			case "NaN" -> IchorUtils.NaN;
 			case "POSITIVE_INFINITY" -> IchorUtils.POSITIVE_INFINITY;
@@ -72,13 +71,13 @@ public Object getStatic(Context cx, Scope scope, String name) {
 			case "isSafeInteger" -> IS_SAFE_INTEGER;
 			case "parseFloat" -> PARSE_FLOAT;
 			case "parseInt" -> PARSE_INT;
-			default -> super.getStatic(cx, scope, name);
+			default -> super.getStatic(scope, name);
 		};
 	}
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, Number self, String name) {
+	public Object getLocal(Scope scope, Number self, String name) {
 		return switch (name) {
 			case "millis", "ms" -> Duration.ofMillis(self.longValue());
 			case "seconds", "s" -> Duration.ofSeconds(self.longValue());
@@ -95,38 +94,38 @@ public Object getLocal(Context cx, Scope scope, Number self, String name) {
 			case "toFloat" -> TO_FLOAT.with(self);
 			case "toDouble" -> TO_DOUBLE.with(self);
 			case "toChar" -> TO_CHAR.with(self);
-			default -> super.getLocal(cx, scope, self, name);
+			default -> super.getLocal(scope, self, name);
 		};
 	}
 
 	@Override
-	public Collection<?> keys(Context cx, Scope scope, Number self) {
+	public Collection<?> keys(Scope scope, Number self) {
 		return List.of();
 	}
 
 	@Override
-	public Collection<?> values(Context cx, Scope scope, Number self) {
+	public Collection<?> values(Scope scope, Number self) {
 		return List.of();
 	}
 
 	@Override
-	public Collection<?> entries(Context cx, Scope scope, Number self) {
+	public Collection<?> entries(Scope scope, Number self) {
 		return List.of();
 	}
 
 	@Override
-	public boolean asString(Context cx, Scope scope, Number self, StringBuilder builder, boolean escape) {
+	public boolean asString(Scope scope, Number self, StringBuilder builder, boolean escape) {
 		AstStringBuilder.wrapNumber(self, builder);
 		return true;
 	}
 
 	@Override
-	public Number asNumber(Context cx, Scope scope, Number self) {
+	public Number asNumber(Scope scope, Number self) {
 		return self;
 	}
 
 	@Override
-	public Boolean asBoolean(Context cx, Scope scope, Number self) {
+	public Boolean asBoolean(Scope scope, Number self) {
 		return self.doubleValue() != 0D;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/type/ObjectJS.java b/src/main/java/dev/latvian/apps/ichor/type/ObjectJS.java
index 9cd7faf..a7e3f79 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/ObjectJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/ObjectJS.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.type;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.prototype.Prototype;
 import dev.latvian.apps.ichor.util.Functions;
@@ -11,10 +10,10 @@
 import java.util.List;
 
 public class ObjectJS extends Prototype<ObjectJS> {
-	public static final Callable ASSIGN = Functions.of2((cx, scope, arg1, arg2) -> {
-		var o = cx.asMap(scope, arg1);
+	public static final Callable ASSIGN = Functions.of2((scope, arg1, arg2) -> {
+		var o = scope.asMap(arg1);
 		//noinspection unchecked
-		o.putAll(cx.asMap(scope, arg2));
+		o.putAll(scope.asMap(arg2));
 		return o;
 	});
 
@@ -22,38 +21,38 @@ public class ObjectJS extends Prototype<ObjectJS> {
 	public static final Callable DEFINE_PROPERTIES = Functions.WIP;
 	public static final Callable DEFINE_PROPERTY = Functions.WIP;
 
-	public static final Callable ENTRIES = Functions.of1((cx, scope, arg) -> {
-		var p = cx.getPrototype(scope, arg);
-		var c = p.entries(cx, scope, p.cast(arg));
+	public static final Callable ENTRIES = Functions.of1((scope, arg) -> {
+		var p = scope.getPrototype(arg);
+		var c = p.entries(scope, p.cast(arg));
 		return c == null ? List.of() : c;
 	});
 
-	public static final Callable KEYS = Functions.of1((cx, scope, arg) -> {
-		var p = cx.getPrototype(scope, arg);
-		var c = p.keys(cx, scope, p.cast(arg));
+	public static final Callable KEYS = Functions.of1((scope, arg) -> {
+		var p = scope.getPrototype(arg);
+		var c = p.keys(scope, p.cast(arg));
 		return c == null ? List.of() : c;
 	});
 
-	public static final Callable VALUES = Functions.of1((cx, scope, arg) -> {
-		var p = cx.getPrototype(scope, arg);
-		var c = p.values(cx, scope, p.cast(arg));
+	public static final Callable VALUES = Functions.of1((scope, arg) -> {
+		var p = scope.getPrototype(arg);
+		var c = p.values(scope, p.cast(arg));
 		return c == null ? List.of() : c;
 	});
 
-	public static final Callable GET_PROTOTYPE_OF = Functions.of1(Context::getPrototype);
+	public static final Callable GET_PROTOTYPE_OF = Functions.of1(Scope::getPrototype);
 
-	public ObjectJS(Context cx) {
+	public ObjectJS(Scope cx) {
 		super(cx, "Object", ObjectJS.class);
 	}
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
 		return new LinkedHashMap<>();
 	}
 
 	@Override
 	@Nullable
-	public Object getStatic(Context cx, Scope scope, String name) {
+	public Object getStatic(Scope scope, String name) {
 		return switch (name) {
 			case "assign" -> ASSIGN;
 			case "create" -> CREATE;
@@ -63,7 +62,7 @@ public Object getStatic(Context cx, Scope scope, String name) {
 			case "keys" -> KEYS;
 			case "values" -> VALUES;
 			case "getPrototypeOf" -> GET_PROTOTYPE_OF;
-			default -> super.getStatic(cx, scope, name);
+			default -> super.getStatic(scope, name);
 		};
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/type/RegExpJS.java b/src/main/java/dev/latvian/apps/ichor/type/RegExpJS.java
index bd601b5..9645558 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/RegExpJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/RegExpJS.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.type;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.error.ArgumentCountMismatchError;
 import dev.latvian.apps.ichor.prototype.Prototype;
@@ -8,12 +7,12 @@
 import java.util.regex.Pattern;
 
 public class RegExpJS extends Prototype<Pattern> {
-	public RegExpJS(Context cx) {
+	public RegExpJS(Scope cx) {
 		super(cx, "RegExp", Pattern.class);
 	}
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
 		if (args.length == 0) {
 			throw new ArgumentCountMismatchError(1, 0);
 		}
@@ -21,7 +20,7 @@ public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
 		int flags = 0;
 
 		if (args.length >= 2) {
-			for (char c : cx.asString(scope, args[1], false).toCharArray()) {
+			for (char c : scope.asString(args[1], false).toCharArray()) {
 				switch (c) {
 					case 'd' -> flags |= Pattern.UNIX_LINES;
 					case 'i' -> flags |= Pattern.CASE_INSENSITIVE;
@@ -35,11 +34,11 @@ public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
 			}
 		}
 
-		return Pattern.compile(cx.asString(scope, args[0], false), flags);
+		return Pattern.compile(scope.asString(args[0], false), flags);
 	}
 
 	@Override
-	public boolean asString(Context cx, Scope scope, Pattern self, StringBuilder builder, boolean escape) {
+	public boolean asString(Scope scope, Pattern self, StringBuilder builder, boolean escape) {
 		builder.append('/');
 		builder.append(self.pattern());
 		builder.append('/');
diff --git a/src/main/java/dev/latvian/apps/ichor/type/SetJS.java b/src/main/java/dev/latvian/apps/ichor/type/SetJS.java
index 1c47e01..d8837dd 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/SetJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/SetJS.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.type;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.prototype.Prototype;
@@ -15,19 +14,19 @@
 
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class SetJS extends Prototype<Set> {
-	public static final Functions.Bound<Set> ADD = (cx, scope, self, args) -> {
+	public static final Functions.Bound<Set> ADD = (scope, self, args) -> {
 		self.add(args[0]);
 		return self;
 	};
 
-	public static final Functions.Bound<Set> CLEAR = (cx, scope, self, args) -> {
+	public static final Functions.Bound<Set> CLEAR = (scope, self, args) -> {
 		self.clear();
 		return Special.UNDEFINED;
 	};
 
-	public static final Functions.Bound<Set> DELETE = (cx, scope, self, args) -> self.remove(args[0]);
+	public static final Functions.Bound<Set> DELETE = (scope, self, args) -> self.remove(args[0]);
 
-	public static final Functions.Bound<Set> ENTRIES = (cx, scope, self, args) -> {
+	public static final Functions.Bound<Set> ENTRIES = (scope, self, args) -> {
 		var entries = new List[self.size()];
 		int i = 0;
 
@@ -39,31 +38,31 @@ public class SetJS extends Prototype<Set> {
 		return Arrays.asList(entries).iterator();
 	};
 
-	public static final Functions.Bound<Set> HAS = (cx, scope, self, args) -> self.contains(args[0]);
-	public static final Functions.Bound<Set> VALUES = (cx, scope, self, args) -> self.iterator();
+	public static final Functions.Bound<Set> HAS = (scope, self, args) -> self.contains(args[0]);
+	public static final Functions.Bound<Set> VALUES = (scope, self, args) -> self.iterator();
 
-	public SetJS(Context cx) {
+	public SetJS(Scope cx) {
 		super(cx, "Set", Set.class);
 	}
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
 		return new LinkedHashSet<>();
 	}
 
 	@Override
-	public Collection<?> keys(Context cx, Scope scope, Set self) {
+	public Collection<?> keys(Scope scope, Set self) {
 		return self;
 	}
 
 	@Override
-	public Collection<?> values(Context cx, Scope scope, Set self) {
+	public Collection<?> values(Scope scope, Set self) {
 		return self;
 	}
 
 	@Override
 	@Nullable
-	public Object getLocal(Context cx, Scope scope, Set self, String name) {
+	public Object getLocal(Scope scope, Set self, String name) {
 		return switch (name) {
 			case "length", "size" -> self.size();
 			case "add" -> ADD.with(self);
@@ -73,17 +72,17 @@ public Object getLocal(Context cx, Scope scope, Set self, String name) {
 			case "has" -> HAS.with(self);
 			case "keys", "values" -> VALUES.with(self);
 			case "forEach" -> IterableJS.FOR_EACH.with(self);
-			default -> super.getStatic(cx, scope, name);
+			default -> super.getStatic(scope, name);
 		};
 	}
 
 	@Override
-	public int getLength(Context cx, Scope scope, Object self) {
+	public int getLength(Scope scope, Object self) {
 		return ((Set) self).size();
 	}
 
 	@Override
-	public Collection<?> entries(Context cx, Scope scope, Set self) {
+	public Collection<?> entries(Scope scope, Set self) {
 		if (self.isEmpty()) {
 			return List.of();
 		} else if (self.size() == 1) {
diff --git a/src/main/java/dev/latvian/apps/ichor/type/StringJS.java b/src/main/java/dev/latvian/apps/ichor/type/StringJS.java
index edcd378..d7bbf1a 100644
--- a/src/main/java/dev/latvian/apps/ichor/type/StringJS.java
+++ b/src/main/java/dev/latvian/apps/ichor/type/StringJS.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.type;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.AstStringBuilder;
 import dev.latvian.apps.ichor.error.ScriptError;
@@ -25,17 +24,17 @@ public InvalidCodePointError(String codePoint) {
 		}
 	}
 
-	private static final Callable RAW = Functions.ofN((cx, scope, args) -> {
+	private static final Callable RAW = Functions.ofN((scope, args) -> {
 		var sb = new StringBuilder();
 
 		for (var o : JavaArray.of(args[0])) {
-			sb.append(cx.asString(scope, o, false));
+			sb.append(scope.asString(o, false));
 		}
 
 		return sb.toString();
 	});
 
-	private static final Callable FROM_CHAR_CODE = Functions.ofN((cx, scope, args) -> {
+	private static final Callable FROM_CHAR_CODE = Functions.ofN((scope, args) -> {
 		int n = args.length;
 
 		if (n < 1) {
@@ -45,13 +44,13 @@ public InvalidCodePointError(String codePoint) {
 		var chars = new char[n];
 
 		for (int i = 0; i != n; ++i) {
-			chars[i] = cx.asChar(scope, args[i]);
+			chars[i] = scope.asChar(args[i]);
 		}
 
 		return new String(chars);
 	});
 
-	private static final Callable FROM_CODE_POINT = Functions.ofN((cx, scope, args) -> {
+	private static final Callable FROM_CODE_POINT = Functions.ofN((scope, args) -> {
 		int n = args.length;
 
 		if (n < 1) {
@@ -61,10 +60,10 @@ public InvalidCodePointError(String codePoint) {
 		var codePoints = new int[n];
 
 		for (int i = 0; i != n; i++) {
-			int codePoint = cx.asInt(scope, args[i]);
+			int codePoint = scope.asInt(args[i]);
 
 			if (!Character.isValidCodePoint(codePoint)) {
-				throw new InvalidCodePointError(cx.asString(scope, args[i], true));
+				throw new InvalidCodePointError(scope.asString(args[i], true));
 			}
 
 			codePoints[i] = codePoint;
@@ -73,33 +72,33 @@ public InvalidCodePointError(String codePoint) {
 		return new String(codePoints, 0, n);
 	});
 
-	private static final Functions.Bound<String> CHAR_AT = (cx, scope, str, args) -> str.charAt(cx.asInt(scope, args[0]));
-	private static final Functions.Bound<String> TRIM = (cx, scope, str, args) -> str.trim();
+	private static final Functions.Bound<String> CHAR_AT = (scope, str, args) -> str.charAt(scope.asInt(args[0]));
+	private static final Functions.Bound<String> TRIM = (scope, str, args) -> str.trim();
 
-	public StringJS(Context cx) {
-		super(cx, "String", String.class);
+	public StringJS(Scope scope) {
+		super(scope, "String", String.class);
 	}
 
 	@Override
-	public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
-		return args.length == 0 ? "" : cx.asString(scope, args[0], false);
+	public Object call(Scope scope, Object[] args, boolean hasNew) {
+		return args.length == 0 ? "" : scope.asString(args[0], false);
 	}
 
 	@Override
 	@Nullable
-	public Object getStatic(Context cx, Scope scope, String name) {
+	public Object getStatic(Scope scope, String name) {
 		return switch (name) {
 			case "raw" -> RAW;
 			case "fromCharCode" -> FROM_CHAR_CODE;
 			case "fromCodePoint" -> FROM_CODE_POINT;
-			default -> super.getStatic(cx, scope, name);
+			default -> super.getStatic(scope, name);
 		};
 	}
 
 	@Override
 	@Nullable
 	@SuppressWarnings("DuplicateBranchesInSwitch")
-	public Object getLocal(Context cx, Scope scope, String self, String name) {
+	public Object getLocal(Scope scope, String self, String name) {
 		return switch (name) {
 			case "length" -> self.length();
 			case "charAt" -> CHAR_AT.with(self);
@@ -132,17 +131,17 @@ public Object getLocal(Context cx, Scope scope, String self, String name) {
 			case "padEnd" -> Functions.WIP;
 			case "trimStart" -> Functions.WIP;
 			case "trimEnd" -> Functions.WIP;
-			default -> super.getLocal(cx, scope, self, name);
+			default -> super.getLocal(scope, self, name);
 		};
 	}
 
 	@Override
-	public int getLength(Context cx, Scope scope, Object self) {
+	public int getLength(Scope scope, Object self) {
 		return ((CharSequence) self).length();
 	}
 
 	@Override
-	public Collection<?> keys(Context cx, Scope scope, String self) {
+	public Collection<?> keys(Scope scope, String self) {
 		if (self.isEmpty()) {
 			return List.of();
 		}
@@ -157,7 +156,7 @@ public Collection<?> keys(Context cx, Scope scope, String self) {
 	}
 
 	@Override
-	public Collection<?> values(Context cx, Scope scope, String self) {
+	public Collection<?> values(Scope scope, String self) {
 		if (self.isEmpty()) {
 			return List.of();
 		}
@@ -172,7 +171,7 @@ public Collection<?> values(Context cx, Scope scope, String self) {
 	}
 
 	@Override
-	public Collection<?> entries(Context cx, Scope scope, String self) {
+	public Collection<?> entries(Scope scope, String self) {
 		if (self.isEmpty()) {
 			return List.of();
 		}
@@ -187,7 +186,7 @@ public Collection<?> entries(Context cx, Scope scope, String self) {
 	}
 
 	@Override
-	public boolean asString(Context cx, Scope scope, String self, StringBuilder builder, boolean escape) {
+	public boolean asString(Scope scope, String self, StringBuilder builder, boolean escape) {
 		if (escape) {
 			AstStringBuilder.wrapString(self, builder);
 		} else {
@@ -198,7 +197,7 @@ public boolean asString(Context cx, Scope scope, String self, StringBuilder buil
 	}
 
 	@Override
-	public Number asNumber(Context cx, Scope scope, String self) {
+	public Number asNumber(Scope scope, String self) {
 		try {
 			return IchorUtils.parseNumber(self);
 		} catch (NumberFormatException ex) {
@@ -207,7 +206,7 @@ public Number asNumber(Context cx, Scope scope, String self) {
 	}
 
 	@Override
-	public Boolean asBoolean(Context cx, Scope scope, String self) {
+	public Boolean asBoolean(Scope scope, String self) {
 		return !self.isEmpty();
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/util/ClassFunctionInstance.java b/src/main/java/dev/latvian/apps/ichor/util/ClassFunctionInstance.java
index 90333fd..d5976cf 100644
--- a/src/main/java/dev/latvian/apps/ichor/util/ClassFunctionInstance.java
+++ b/src/main/java/dev/latvian/apps/ichor/util/ClassFunctionInstance.java
@@ -1,13 +1,12 @@
 package dev.latvian.apps.ichor.util;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.expression.AstClassFunction;
 
 public class ClassFunctionInstance extends FunctionInstance {
 
-	public ClassFunctionInstance(AstClassFunction function, Context evalContext, Scope evalScope) {
-		super(function, evalContext, evalScope);
+	public ClassFunctionInstance(AstClassFunction function, Scope evalScope) {
+		super(function, evalScope);
 	}
 
 	/*
@@ -22,11 +21,11 @@ public String getPrototypeName() {
 	 */
 
 	@Override
-	public Object call(Context cx, Scope callScope, Object[] args, boolean hasNew) {
+	public Object call(Scope callScope, Object[] args, boolean hasNew) {
 		if (function == ((AstClassFunction) function).owner.constructor) {
-			return super.call(cx, callScope, args, false);
+			return super.call(callScope, args, false);
 		} else {
-			return super.call(cx, callScope, args, hasNew);
+			return super.call(callScope, args, hasNew);
 		}
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/util/ClassPrototype.java b/src/main/java/dev/latvian/apps/ichor/util/ClassPrototype.java
index 7de58cf..280ff53 100644
--- a/src/main/java/dev/latvian/apps/ichor/util/ClassPrototype.java
+++ b/src/main/java/dev/latvian/apps/ichor/util/ClassPrototype.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.util;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.ast.statement.AstClass;
 import dev.latvian.apps.ichor.slot.Slot;
@@ -18,12 +17,12 @@ public ClassPrototype(AstClass astClass, Scope classEvalScope) {
 	}
 
 	@Override
-	public Object call(Context cx, Scope callScope, Object[] args, boolean hasNew) {
-		var instance = new Instance(cx, this);
+	public Object call(Scope callScope, Object[] args, boolean hasNew) {
+		var instance = new Instance(this);
 
 		if (astClass.constructor != null) {
-			var ctor = astClass.constructor.eval(cx, callScope);
-			ctor.call(cx, callScope, args, true);
+			var ctor = astClass.constructor.eval(callScope);
+			ctor.call(callScope, args, true);
 		}
 
 		return instance;
@@ -32,13 +31,13 @@ public Object call(Context cx, Scope callScope, Object[] args, boolean hasNew) {
 	public static final class Instance extends Scope {
 		public final ClassPrototype prototype;
 
-		public Instance(Context cx, ClassPrototype prototype) {
+		public Instance(ClassPrototype prototype) {
 			super(prototype.classEvalScope.push());
 			setScopeThis(this);
 			this.prototype = prototype;
 
 			for (var func : prototype.astClass.methods.values()) {
-				add(func.functionName, new ClassFunctionInstance(func, cx, this), Slot.DEFAULT);
+				add(func.functionName, new ClassFunctionInstance(func, this), Slot.DEFAULT);
 			}
 		}
 
diff --git a/src/main/java/dev/latvian/apps/ichor/util/EvaluableConstant.java b/src/main/java/dev/latvian/apps/ichor/util/EvaluableConstant.java
index ad39387..67b9137 100644
--- a/src/main/java/dev/latvian/apps/ichor/util/EvaluableConstant.java
+++ b/src/main/java/dev/latvian/apps/ichor/util/EvaluableConstant.java
@@ -1,13 +1,12 @@
 package dev.latvian.apps.ichor.util;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Evaluable;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 
 public record EvaluableConstant(Object value) implements Evaluable {
 	@Override
-	public Object eval(Context cx, Scope scope) {
+	public Object eval(Scope scope) {
 		return value == Special.NULL ? null : value;
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/util/FunctionInstance.java b/src/main/java/dev/latvian/apps/ichor/util/FunctionInstance.java
index 7277da5..e164339 100644
--- a/src/main/java/dev/latvian/apps/ichor/util/FunctionInstance.java
+++ b/src/main/java/dev/latvian/apps/ichor/util/FunctionInstance.java
@@ -1,7 +1,6 @@
 package dev.latvian.apps.ichor.util;
 
 import dev.latvian.apps.ichor.CallableTypeAdapter;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.Special;
 import dev.latvian.apps.ichor.ast.expression.AstFunction;
@@ -13,17 +12,15 @@
 
 public class FunctionInstance implements CallableTypeAdapter {
 	public final AstFunction function;
-	public final Context evalContext;
 	public final Scope evalScope;
 
-	public FunctionInstance(AstFunction function, Context evalContext, Scope evalScope) {
+	public FunctionInstance(AstFunction function, Scope evalScope) {
 		this.function = function;
-		this.evalContext = evalContext;
 		this.evalScope = evalScope;
 	}
 
 	@Override
-	public Object call(Context cx, Scope callScope, Object[] args, boolean hasNew) {
+	public Object call(Scope callScope, Object[] args, boolean hasNew) {
 		if (hasNew) {
 			throw new ConstructorError(null);
 		} else if (args.length < function.requiredParams) {
@@ -46,7 +43,7 @@ public Object call(Context cx, Scope callScope, Object[] args, boolean hasNew) {
 					if (function.params[i].defaultValue == Special.UNDEFINED) {
 						value = Special.UNDEFINED;
 					} else {
-						value = evalContext.eval(s, function.params[i].defaultValue);
+						value = s.eval(function.params[i].defaultValue);
 					}
 				} else {
 					value = args[i];
@@ -56,7 +53,7 @@ public Object call(Context cx, Scope callScope, Object[] args, boolean hasNew) {
 				s.addMutable(function.params[i].name, value);
 			}
 
-			function.body.interpretSafe(evalContext, s);
+			function.body.interpretSafe(s);
 		} catch (ReturnExit exit) {
 			if (function.hasMod(AstFunction.Mod.ASYNC)) {
 				return CompletableFuture.completedFuture(exit.value);
@@ -68,11 +65,6 @@ public Object call(Context cx, Scope callScope, Object[] args, boolean hasNew) {
 		return Special.UNDEFINED;
 	}
 
-	@Override
-	public Context getEvalContext() {
-		return evalContext;
-	}
-
 	@Override
 	public Scope getEvalScope() {
 		return evalScope;
diff --git a/src/main/java/dev/latvian/apps/ichor/util/Functions.java b/src/main/java/dev/latvian/apps/ichor/util/Functions.java
index d4a36ce..ea0f787 100644
--- a/src/main/java/dev/latvian/apps/ichor/util/Functions.java
+++ b/src/main/java/dev/latvian/apps/ichor/util/Functions.java
@@ -1,13 +1,12 @@
 package dev.latvian.apps.ichor.util;
 
 import dev.latvian.apps.ichor.Callable;
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.error.ArgumentCountMismatchError;
 import dev.latvian.apps.ichor.error.WIPFeatureError;
 
 public class Functions {
-	public static final Callable WIP = (cx, scope, args, hasNew) -> {
+	public static final Callable WIP = (scope, args, hasNew) -> {
 		throw new WIPFeatureError();
 	};
 
@@ -29,7 +28,7 @@ public static Callable of3(Arg3 function) {
 
 	@FunctionalInterface
 	public interface Bound<T> {
-		Object call(Context cx, Scope scope, T self, Object[] args);
+		Object call(Scope scope, T self, Object[] args);
 
 		default Callable with(T self) {
 			return new BoundCallable<>(self, this);
@@ -38,60 +37,60 @@ default Callable with(T self) {
 
 	public record BoundCallable<T>(T self, Bound<T> function) implements Callable {
 		@Override
-		public Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
-			return function.call(cx, scope, self, args);
+		public Object call(Scope scope, Object[] args, boolean hasNew) {
+			return function.call(scope, self, args);
 		}
 	}
 
 	@FunctionalInterface
 	public interface ArgN extends Callable {
-		Object call(Context cx, Scope scope, Object[] args);
+		Object call(Scope scope, Object[] args);
 
 		@Override
-		default Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
-			return call(cx, scope, args);
+		default Object call(Scope scope, Object[] args, boolean hasNew) {
+			return call(scope, args);
 		}
 	}
 
 	@FunctionalInterface
 	public interface Arg1 extends Callable {
-		Object call(Context cx, Scope scope, Object arg);
+		Object call(Scope scope, Object arg);
 
 		@Override
-		default Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+		default Object call(Scope scope, Object[] args, boolean hasNew) {
 			if (args.length < 1) {
 				throw new ArgumentCountMismatchError(1, args.length);
 			}
 
-			return call(cx, scope, args[0]);
+			return call(scope, args[0]);
 		}
 	}
 
 	@FunctionalInterface
 	public interface Arg2 extends Callable {
-		Object call(Context cx, Scope scope, Object arg1, Object arg2);
+		Object call(Scope scope, Object arg1, Object arg2);
 
 		@Override
-		default Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+		default Object call(Scope scope, Object[] args, boolean hasNew) {
 			if (args.length < 2) {
 				throw new ArgumentCountMismatchError(2, args.length);
 			}
 
-			return call(cx, scope, args[0], args[1]);
+			return call(scope, args[0], args[1]);
 		}
 	}
 
 	@FunctionalInterface
 	public interface Arg3 extends Callable {
-		Object call(Context cx, Scope scope, Object arg1, Object arg2, Object arg3);
+		Object call(Scope scope, Object arg1, Object arg2, Object arg3);
 
 		@Override
-		default Object call(Context cx, Scope scope, Object[] args, boolean hasNew) {
+		default Object call(Scope scope, Object[] args, boolean hasNew) {
 			if (args.length < 3) {
 				throw new ArgumentCountMismatchError(3, args.length);
 			}
 
-			return call(cx, scope, args[0], args[1], args[2]);
+			return call(scope, args[0], args[1], args[2]);
 		}
 	}
 }
diff --git a/src/main/java/dev/latvian/apps/ichor/util/IchorUtils.java b/src/main/java/dev/latvian/apps/ichor/util/IchorUtils.java
index 28c8eb1..438f5bb 100644
--- a/src/main/java/dev/latvian/apps/ichor/util/IchorUtils.java
+++ b/src/main/java/dev/latvian/apps/ichor/util/IchorUtils.java
@@ -30,41 +30,41 @@ public interface IchorUtils {
 
 	Integer[] DIGITS = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 
-	Callable ABS = Functions.of1((cx, scope, arg) -> Math.abs(cx.asDouble(scope, arg)));
-	Callable ACOS = Functions.of1((cx, scope, arg) -> Math.acos(cx.asDouble(scope, arg)));
-	Callable ASIN = Functions.of1((cx, scope, arg) -> Math.asin(cx.asDouble(scope, arg)));
-	Callable ATAN = Functions.of1((cx, scope, arg) -> Math.atan(cx.asDouble(scope, arg)));
-	Callable ATAN2 = Functions.of2((cx, scope, arg1, arg2) -> Math.atan2(cx.asDouble(scope, arg1), cx.asDouble(scope, arg2)));
-	Callable CEIL = Functions.of1((cx, scope, arg) -> Math.ceil(cx.asDouble(scope, arg)));
-	Callable COS = Functions.of1((cx, scope, arg) -> Math.cos(cx.asDouble(scope, arg)));
-	Callable EXP = Functions.of1((cx, scope, arg) -> Math.exp(cx.asDouble(scope, arg)));
-	Callable FLOOR = Functions.of1((cx, scope, arg) -> Math.floor(cx.asDouble(scope, arg)));
-	Callable LOG = Functions.of1((cx, scope, arg) -> Math.log(cx.asDouble(scope, arg)));
-	Callable MAX = Functions.of2((cx, scope, arg1, arg2) -> Math.max(cx.asDouble(scope, arg1), cx.asDouble(scope, arg2)));
-	Callable MIN = Functions.of2((cx, scope, arg1, arg2) -> Math.min(cx.asDouble(scope, arg1), cx.asDouble(scope, arg2)));
-	Callable POW = Functions.of2((cx, scope, arg1, arg2) -> Math.pow(cx.asDouble(scope, arg1), cx.asDouble(scope, arg2)));
-	Callable RANDOM = Functions.ofN((cx, scope, args) -> Math.random());
-	Callable ROUND = Functions.of1((cx, scope, arg) -> Math.round(cx.asDouble(scope, arg)));
-	Callable SIN = Functions.of1((cx, scope, arg) -> Math.sin(cx.asDouble(scope, arg)));
-	Callable SQRT = Functions.of1((cx, scope, arg) -> Math.sqrt(cx.asDouble(scope, arg)));
-	Callable TAN = Functions.of1((cx, scope, arg) -> Math.tan(cx.asDouble(scope, arg)));
-	Callable CBRT = Functions.of1((cx, scope, arg) -> Math.cbrt(cx.asDouble(scope, arg)));
-	Callable COSH = Functions.of1((cx, scope, arg) -> Math.cosh(cx.asDouble(scope, arg)));
-	Callable EXPM1 = Functions.of1((cx, scope, arg) -> Math.expm1(cx.asDouble(scope, arg)));
-	Callable HYPOT = Functions.of2((cx, scope, arg1, arg2) -> Math.hypot(cx.asDouble(scope, arg1), cx.asDouble(scope, arg2)));
-	Callable LOG1P = Functions.of1((cx, scope, arg) -> Math.log1p(cx.asDouble(scope, arg)));
-	Callable LOG10 = Functions.of1((cx, scope, arg) -> Math.log10(cx.asDouble(scope, arg)));
-	Callable SINH = Functions.of1((cx, scope, arg) -> Math.sinh(cx.asDouble(scope, arg)));
-	Callable TANH = Functions.of1((cx, scope, arg) -> Math.tanh(cx.asDouble(scope, arg)));
-	Callable IMUL = Functions.of2((cx, scope, arg1, arg2) -> Math.multiplyExact(cx.asInt(scope, arg1), cx.asInt(scope, arg2)));
-
-	Callable TRUNC = Functions.of1((cx, scope, arg) -> {
-		var x = cx.asDouble(scope, arg);
+	Callable ABS = Functions.of1((scope, arg) -> Math.abs(scope.asDouble(arg)));
+	Callable ACOS = Functions.of1((scope, arg) -> Math.acos(scope.asDouble(arg)));
+	Callable ASIN = Functions.of1((scope, arg) -> Math.asin(scope.asDouble(arg)));
+	Callable ATAN = Functions.of1((scope, arg) -> Math.atan(scope.asDouble(arg)));
+	Callable ATAN2 = Functions.of2((scope, arg1, arg2) -> Math.atan2(scope.asDouble(arg1), scope.asDouble(arg2)));
+	Callable CEIL = Functions.of1((scope, arg) -> Math.ceil(scope.asDouble(arg)));
+	Callable COS = Functions.of1((scope, arg) -> Math.cos(scope.asDouble(arg)));
+	Callable EXP = Functions.of1((scope, arg) -> Math.exp(scope.asDouble(arg)));
+	Callable FLOOR = Functions.of1((scope, arg) -> Math.floor(scope.asDouble(arg)));
+	Callable LOG = Functions.of1((scope, arg) -> Math.log(scope.asDouble(arg)));
+	Callable MAX = Functions.of2((scope, arg1, arg2) -> Math.max(scope.asDouble(arg1), scope.asDouble(arg2)));
+	Callable MIN = Functions.of2((scope, arg1, arg2) -> Math.min(scope.asDouble(arg1), scope.asDouble(arg2)));
+	Callable POW = Functions.of2((scope, arg1, arg2) -> Math.pow(scope.asDouble(arg1), scope.asDouble(arg2)));
+	Callable RANDOM = Functions.ofN((scope, args) -> Math.random());
+	Callable ROUND = Functions.of1((scope, arg) -> Math.round(scope.asDouble(arg)));
+	Callable SIN = Functions.of1((scope, arg) -> Math.sin(scope.asDouble(arg)));
+	Callable SQRT = Functions.of1((scope, arg) -> Math.sqrt(scope.asDouble(arg)));
+	Callable TAN = Functions.of1((scope, arg) -> Math.tan(scope.asDouble(arg)));
+	Callable CBRT = Functions.of1((scope, arg) -> Math.cbrt(scope.asDouble(arg)));
+	Callable COSH = Functions.of1((scope, arg) -> Math.cosh(scope.asDouble(arg)));
+	Callable EXPM1 = Functions.of1((scope, arg) -> Math.expm1(scope.asDouble(arg)));
+	Callable HYPOT = Functions.of2((scope, arg1, arg2) -> Math.hypot(scope.asDouble(arg1), scope.asDouble(arg2)));
+	Callable LOG1P = Functions.of1((scope, arg) -> Math.log1p(scope.asDouble(arg)));
+	Callable LOG10 = Functions.of1((scope, arg) -> Math.log10(scope.asDouble(arg)));
+	Callable SINH = Functions.of1((scope, arg) -> Math.sinh(scope.asDouble(arg)));
+	Callable TANH = Functions.of1((scope, arg) -> Math.tanh(scope.asDouble(arg)));
+	Callable IMUL = Functions.of2((scope, arg1, arg2) -> Math.multiplyExact(scope.asInt(arg1), scope.asInt(arg2)));
+
+	Callable TRUNC = Functions.of1((scope, arg) -> {
+		var x = scope.asDouble(arg);
 		return x < 0.0 ? Math.ceil(x) : Math.floor(x);
 	});
 
-	Callable ACOSH = Functions.of1((cx, scope, arg) -> {
-		var x = cx.asDouble(scope, arg);
+	Callable ACOSH = Functions.of1((scope, arg) -> {
+		var x = scope.asDouble(arg);
 
 		if (!Double.isNaN(x)) {
 			return Math.log(x + Math.sqrt(x * x - 1.0));
@@ -73,8 +73,8 @@ public interface IchorUtils {
 		return NaN;
 	});
 
-	Callable ASINH = Functions.of1((cx, scope, arg) -> {
-		var x = cx.asDouble(scope, arg);
+	Callable ASINH = Functions.of1((scope, arg) -> {
+		var x = scope.asDouble(arg);
 
 		if (Double.isInfinite(x)) {
 			return x;
@@ -87,8 +87,8 @@ public interface IchorUtils {
 		return NaN;
 	});
 
-	Callable ATANH = Functions.of1((cx, scope, arg) -> {
-		var x = cx.asDouble(scope, arg);
+	Callable ATANH = Functions.of1((scope, arg) -> {
+		var x = scope.asDouble(arg);
 
 		if (!Double.isNaN(x) && -1.0 <= x && x <= 1.0) {
 			return x == 0.0 ? 1.0 / x > 0.0 ? ZERO : NZERO : 0.5 * Math.log((x + 1.0) / (x - 1.0));
@@ -97,12 +97,12 @@ public interface IchorUtils {
 		return NaN;
 	});
 
-	Callable SIGN = Functions.of1((cx, scope, arg) -> Math.signum(cx.asDouble(scope, arg)));
-	Callable LOG2 = Functions.of1((cx, scope, arg) -> Math.log(cx.asDouble(scope, arg)) * LOG2E);
-	Callable FROUND = Functions.of1((cx, scope, arg) -> (float) cx.asDouble(scope, arg));
+	Callable SIGN = Functions.of1((scope, arg) -> Math.signum(scope.asDouble(arg)));
+	Callable LOG2 = Functions.of1((scope, arg) -> Math.log(scope.asDouble(arg)) * LOG2E);
+	Callable FROUND = Functions.of1((scope, arg) -> (float) scope.asDouble(arg));
 
-	Callable CLZ32 = Functions.of1((cx, scope, arg) -> {
-		var x = cx.asDouble(scope, arg);
+	Callable CLZ32 = Functions.of1((scope, arg) -> {
+		var x = scope.asDouble(arg);
 
 		if (x == 0 || Double.isNaN(x) || Double.isInfinite(x)) {
 			return D32;
diff --git a/src/main/java/dev/latvian/apps/ichor/util/JavaArray.java b/src/main/java/dev/latvian/apps/ichor/util/JavaArray.java
index d5d2678..ca06f01 100644
--- a/src/main/java/dev/latvian/apps/ichor/util/JavaArray.java
+++ b/src/main/java/dev/latvian/apps/ichor/util/JavaArray.java
@@ -1,6 +1,5 @@
 package dev.latvian.apps.ichor.util;
 
-import dev.latvian.apps.ichor.Context;
 import dev.latvian.apps.ichor.Scope;
 import dev.latvian.apps.ichor.TypeAdapter;
 
@@ -52,7 +51,7 @@ public int size() {
 
 	@Override
 	@SuppressWarnings("unchecked")
-	public <T> T adapt(Context cx, Scope scope, Class<T> type) {
+	public <T> T adapt(Scope scope, Class<T> type) {
 		if (type == array.getClass()) {
 			return (T) array;
 		} else if (type.isArray()) {
@@ -60,7 +59,7 @@ public <T> T adapt(Context cx, Scope scope, Class<T> type) {
 			var arr = Array.newInstance(cType, size());
 
 			for (int i = 0; i < size(); i++) {
-				Array.set(arr, i, cx.as(scope, get(i), cType));
+				Array.set(arr, i, scope.as(get(i), cType));
 			}
 
 			return (T) arr;
@@ -69,14 +68,14 @@ public <T> T adapt(Context cx, Scope scope, Class<T> type) {
 		return null;
 	}
 
-	public static Object adaptToArray(Context cx, Scope scope, Iterable<?> itr, Class<?> toType) {
+	public static Object adaptToArray(Scope scope, Iterable<?> itr, Class<?> toType) {
 		var cType = toType.getComponentType();
 
 		if (itr instanceof List<?> list) {
 			var arr = Array.newInstance(cType, list.size());
 
 			for (int i = 0; i < list.size(); i++) {
-				Array.set(arr, i, cx.as(scope, list.get(i), cType));
+				Array.set(arr, i, scope.as(list.get(i), cType));
 			}
 
 			return arr;
@@ -85,7 +84,7 @@ public static Object adaptToArray(Context cx, Scope scope, Iterable<?> itr, Clas
 			int index = 0;
 
 			for (var o1 : collection) {
-				Array.set(arr, index, cx.as(scope, o1, cType));
+				Array.set(arr, index, scope.as(o1, cType));
 				index++;
 			}
 
@@ -101,7 +100,7 @@ public static Object adaptToArray(Context cx, Scope scope, Iterable<?> itr, Clas
 			int index = 0;
 
 			for (var o1 : itr) {
-				Array.set(arr, index, cx.as(scope, o1, cType));
+				Array.set(arr, index, scope.as(o1, cType));
 				index++;
 			}
 
diff --git a/src/test/java/dev/latvian/apps/ichor/test/InterpreterTests.java b/src/test/java/dev/latvian/apps/ichor/test/InterpreterTests.java
index eff47f0..e3edff4 100644
--- a/src/test/java/dev/latvian/apps/ichor/test/InterpreterTests.java
+++ b/src/test/java/dev/latvian/apps/ichor/test/InterpreterTests.java
@@ -46,9 +46,9 @@ public static void testInterpreter(String filename, String input, Consumer<RootS
 		rootScope.addImmutable("Advanced", new AdvancedTestUtils(console));
 		rootScopeCallback.accept(rootScope);
 
-		var tokenStream = new TokenStream(context, new NamedTokenSource(filename), input);
+		var tokenStream = new TokenStream(context.getTokenStreamTimeout(), new NamedTokenSource(filename), input);
 		var rootToken = tokenStream.getRootToken();
-		var parser = new Parser(context, rootScope, rootToken);
+		var parser = new Parser(rootScope, rootToken);
 		var ast = parser.parse();
 		var astStr = ast.toString();
 
@@ -57,7 +57,7 @@ public static void testInterpreter(String filename, String input, Consumer<RootS
 		System.out.println();
 
 		try {
-			ast.interpretSafe(context, rootScope);
+			ast.interpretSafe(rootScope);
 		} catch (ScopeExit ex) {
 			throw ex;
 		} catch (Throwable ex) {
@@ -751,6 +751,22 @@ public void declareDestructObjNested() {
 				""");
 	}
 
+	@Test
+	public void referenceEdit() {
+		testInterpreter("""
+						let foo = {bar: 2}
+						let baz = foo.bar
+						baz = 1
+						console.log(foo)
+						let baz2 = foo
+						baz2.bar = 1
+						console.log(foo)""",
+				"""
+						{bar: 2}
+						{bar: 1}
+						""");
+	}
+
 	@Test
 	public void z_last() {
 		System.out.println("Hi");
diff --git a/src/test/java/dev/latvian/apps/ichor/test/ParserTests.java b/src/test/java/dev/latvian/apps/ichor/test/ParserTests.java
index 35876d6..2e60aa0 100644
--- a/src/test/java/dev/latvian/apps/ichor/test/ParserTests.java
+++ b/src/test/java/dev/latvian/apps/ichor/test/ParserTests.java
@@ -32,9 +32,9 @@ public static void testParserAst(String filename, String input, String match) {
 
 		System.out.println("Expected: " + match);
 		var cx = new Context();
-		var tokenStream = new TokenStream(cx, new NamedTokenSource(filename), input);
+		var tokenStream = new TokenStream(cx.getTokenStreamTimeout(), new NamedTokenSource(filename), input);
 		var rootToken = tokenStream.getRootToken();
-		var parser = new Parser(cx, new RootScope(cx), rootToken);
+		var parser = new Parser(new RootScope(cx), rootToken);
 		var ast = parser.parse();
 
 		var sb = new AstStringBuilder();
diff --git a/src/test/java/dev/latvian/apps/ichor/test/TokenTests.java b/src/test/java/dev/latvian/apps/ichor/test/TokenTests.java
index 330f600..7d12021 100644
--- a/src/test/java/dev/latvian/apps/ichor/test/TokenTests.java
+++ b/src/test/java/dev/latvian/apps/ichor/test/TokenTests.java
@@ -30,7 +30,7 @@ private static void testTokenStream(String input, Object... match) {
 		System.out.println("--- Token Test ---");
 		System.out.println("Input: " + input);
 		var cx = new Context();
-		var tokenStream = new TokenStream(cx, new NamedTokenSource(""), input);
+		var tokenStream = new TokenStream(cx.getTokenStreamTimeout(), new NamedTokenSource(""), input);
 
 		var current = tokenStream.getRootToken();