diff --git a/src/createContext.ts b/src/createContext.ts
index b6616a456..8243a7c9c 100644
--- a/src/createContext.ts
+++ b/src/createContext.ts
@@ -10,7 +10,7 @@ import * as misc from './stdlib/misc'
 import * as parser from './stdlib/parser'
 import * as stream from './stdlib/stream'
 import { streamPrelude } from './stdlib/stream.prelude'
-import { Context, CustomBuiltIns, Environment, Value, Variant } from './types'
+import { Context, CustomBuiltIns, Environment, NativeStorage, Value, Variant } from './types'
 import * as operators from './utils/operators'
 import * as gpu_lib from './gpu/lib'
 import { stringify } from './utils/stringify'
@@ -112,11 +112,13 @@ export const createGlobalEnvironment = (): Environment => ({
   head: {}
 })
 
-const createNativeStorage = () => ({
-  globals: { variables: new Map(), previousScope: null },
+const createNativeStorage = (): NativeStorage => ({
+  builtins: new Map(),
+  previousProgramsIdentifiers: new Set(),
   operators: new Map(Object.entries(operators)),
   gpu: new Map(Object.entries(gpu_lib)),
-  maxExecTime: JSSLANG_PROPERTIES.maxExecTime
+  maxExecTime: JSSLANG_PROPERTIES.maxExecTime,
+  evaller: null
 })
 
 export const createEmptyContext = <T>(
@@ -171,10 +173,7 @@ export const defineSymbol = (context: Context, name: string, value: Value) => {
     writable: false,
     enumerable: true
   })
-  context.nativeStorage.globals!.variables.set(name, {
-    kind: 'const',
-    getValue: () => value
-  })
+  context.nativeStorage.builtins.set(name, value)
   const typeEnv = context.typeEnvironment[0]
   // if the global type env doesn't already have the imported symbol,
   // we set it to a type var T that can typecheck with anything.
diff --git a/src/index.ts b/src/index.ts
index c73289c7a..44d16b91c 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -489,7 +489,6 @@ export async function runInContext(
     }
     let transpiled
     let sourceMapJson: RawSourceMap | undefined
-    let lastStatementSourceMapJson: RawSourceMap | undefined
     try {
       appendModulesToContext(program, context)
       // Mutates program
@@ -502,11 +501,7 @@ export async function runInContext(
           break
       }
 
-      const temp = transpile(program, context, false)
-      // some issues with formatting and semicolons and tslint so no destructure
-      transpiled = temp.transpiled
-      sourceMapJson = temp.codeMap
-      lastStatementSourceMapJson = temp.evalMap
+      ;({ transpiled, codeMap: sourceMapJson } = transpile(program, context))
       let value = await sandboxedEval(transpiled, context.nativeStorage, context.moduleParams)
       if (context.variant === 'lazy') {
         value = forceIt(value)
@@ -544,24 +539,20 @@ export async function runInContext(
       }
       const line = Number(match![1])
       const column = Number(match![2])
-      return SourceMapConsumer.with(
-        line === 1 ? lastStatementSourceMapJson! : sourceMapJson!,
-        null,
-        consumer => {
-          const {
-            line: originalLine,
-            column: originalColumn,
-            name
-          } = consumer.originalPositionFor({
-            line,
-            column
-          })
-          context.errors.push(
-            convertNativeErrorToSourceError(error, originalLine, originalColumn, name)
-          )
-          return resolvedErrorPromise
-        }
-      )
+      return SourceMapConsumer.with(sourceMapJson!, null, consumer => {
+        const {
+          line: originalLine,
+          column: originalColumn,
+          name
+        } = consumer.originalPositionFor({
+          line,
+          column
+        })
+        context.errors.push(
+          convertNativeErrorToSourceError(error, originalLine, originalColumn, name)
+        )
+        return resolvedErrorPromise
+      })
     }
   } else {
     let it = evaluate(program, context)
diff --git a/src/repl/transpiler.ts b/src/repl/transpiler.ts
index 6726ab166..d2afc6907 100644
--- a/src/repl/transpiler.ts
+++ b/src/repl/transpiler.ts
@@ -29,7 +29,7 @@ function transpileCode(chapter = 1, variant: Variant = 'default', code = '', pre
   if (pretranspile) {
     return generate(program)
   } else {
-    return transpile(program as Program, context, false).transpiled
+    return transpile(program as Program, context).transpiled
   }
 }
 
diff --git a/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap b/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap
index 0f50e7ef3..361c06462 100644
--- a/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap
+++ b/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap
@@ -1,95 +1,96 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Ensure no name clashes 1`] = `
-"const native0 = nativeStorage;
-const callIfFuncAndRightArgs0 = native0.operators.get(\\"callIfFuncAndRightArgs\\");
-const boolOrErr0 = native0.operators.get(\\"boolOrErr\\");
-const wrap90 = native0.operators.get(\\"wrap\\");
-const unaryOp = native0.operators.get(\\"unaryOp\\");
-const binaryOp = native0.operators.get(\\"binaryOp\\");
-const throwIfTimeout = native0.operators.get(\\"throwIfTimeout\\");
-const setProp = native0.operators.get(\\"setProp\\");
-const getProp = native0.operators.get(\\"getProp\\");
-let lastStatementResult = undefined;
-const globals = native0.globals;
-{
-  const get_time = globals.previousScope.variables.get(\\"get_time\\").getValue();
-  const display = globals.previousScope.variables.get(\\"display\\").getValue();
-  const raw_display = globals.previousScope.variables.get(\\"raw_display\\").getValue();
-  const stringify = globals.previousScope.variables.get(\\"stringify\\").getValue();
-  const error = globals.previousScope.variables.get(\\"error\\").getValue();
-  const prompt = globals.previousScope.variables.get(\\"prompt\\").getValue();
-  const is_number = globals.previousScope.variables.get(\\"is_number\\").getValue();
-  const is_string = globals.previousScope.variables.get(\\"is_string\\").getValue();
-  const is_function = globals.previousScope.variables.get(\\"is_function\\").getValue();
-  const is_boolean = globals.previousScope.variables.get(\\"is_boolean\\").getValue();
-  const is_undefined = globals.previousScope.variables.get(\\"is_undefined\\").getValue();
-  const parse_int = globals.previousScope.variables.get(\\"parse_int\\").getValue();
-  const char_at = globals.previousScope.variables.get(\\"char_at\\").getValue();
-  const undefined = globals.previousScope.variables.get(\\"undefined\\").getValue();
-  const NaN = globals.previousScope.variables.get(\\"NaN\\").getValue();
-  const Infinity = globals.previousScope.variables.get(\\"Infinity\\").getValue();
-  const math_abs = globals.previousScope.variables.get(\\"math_abs\\").getValue();
-  const math_acos = globals.previousScope.variables.get(\\"math_acos\\").getValue();
-  const math_acosh = globals.previousScope.variables.get(\\"math_acosh\\").getValue();
-  const math_asin = globals.previousScope.variables.get(\\"math_asin\\").getValue();
-  const math_asinh = globals.previousScope.variables.get(\\"math_asinh\\").getValue();
-  const math_atan = globals.previousScope.variables.get(\\"math_atan\\").getValue();
-  const math_atanh = globals.previousScope.variables.get(\\"math_atanh\\").getValue();
-  const math_atan2 = globals.previousScope.variables.get(\\"math_atan2\\").getValue();
-  const math_ceil = globals.previousScope.variables.get(\\"math_ceil\\").getValue();
-  const math_cbrt = globals.previousScope.variables.get(\\"math_cbrt\\").getValue();
-  const math_expm1 = globals.previousScope.variables.get(\\"math_expm1\\").getValue();
-  const math_clz32 = globals.previousScope.variables.get(\\"math_clz32\\").getValue();
-  const math_cos = globals.previousScope.variables.get(\\"math_cos\\").getValue();
-  const math_cosh = globals.previousScope.variables.get(\\"math_cosh\\").getValue();
-  const math_exp = globals.previousScope.variables.get(\\"math_exp\\").getValue();
-  const math_floor = globals.previousScope.variables.get(\\"math_floor\\").getValue();
-  const math_fround = globals.previousScope.variables.get(\\"math_fround\\").getValue();
-  const math_hypot = globals.previousScope.variables.get(\\"math_hypot\\").getValue();
-  const math_imul = globals.previousScope.variables.get(\\"math_imul\\").getValue();
-  const math_log = globals.previousScope.variables.get(\\"math_log\\").getValue();
-  const math_log1p = globals.previousScope.variables.get(\\"math_log1p\\").getValue();
-  const math_log2 = globals.previousScope.variables.get(\\"math_log2\\").getValue();
-  const math_log10 = globals.previousScope.variables.get(\\"math_log10\\").getValue();
-  const math_max = globals.previousScope.variables.get(\\"math_max\\").getValue();
-  const math_min = globals.previousScope.variables.get(\\"math_min\\").getValue();
-  const math_pow = globals.previousScope.variables.get(\\"math_pow\\").getValue();
-  const math_random = globals.previousScope.variables.get(\\"math_random\\").getValue();
-  const math_round = globals.previousScope.variables.get(\\"math_round\\").getValue();
-  const math_sign = globals.previousScope.variables.get(\\"math_sign\\").getValue();
-  const math_sin = globals.previousScope.variables.get(\\"math_sin\\").getValue();
-  const math_sinh = globals.previousScope.variables.get(\\"math_sinh\\").getValue();
-  const math_sqrt = globals.previousScope.variables.get(\\"math_sqrt\\").getValue();
-  const math_tan = globals.previousScope.variables.get(\\"math_tan\\").getValue();
-  const math_tanh = globals.previousScope.variables.get(\\"math_tanh\\").getValue();
-  const math_trunc = globals.previousScope.variables.get(\\"math_trunc\\").getValue();
-  const math_E = globals.previousScope.variables.get(\\"math_E\\").getValue();
-  const math_LN10 = globals.previousScope.variables.get(\\"math_LN10\\").getValue();
-  const math_LN2 = globals.previousScope.variables.get(\\"math_LN2\\").getValue();
-  const math_LOG10E = globals.previousScope.variables.get(\\"math_LOG10E\\").getValue();
-  const math_LOG2E = globals.previousScope.variables.get(\\"math_LOG2E\\").getValue();
-  const math_PI = globals.previousScope.variables.get(\\"math_PI\\").getValue();
-  const math_SQRT1_2 = globals.previousScope.variables.get(\\"math_SQRT1_2\\").getValue();
-  const math_SQRT2 = globals.previousScope.variables.get(\\"math_SQRT2\\").getValue();
-  const pair = globals.previousScope.variables.get(\\"pair\\").getValue();
-  const is_pair = globals.previousScope.variables.get(\\"is_pair\\").getValue();
-  const head = globals.previousScope.variables.get(\\"head\\").getValue();
-  const tail = globals.previousScope.variables.get(\\"tail\\").getValue();
-  const is_null = globals.previousScope.variables.get(\\"is_null\\").getValue();
-  const list = globals.previousScope.variables.get(\\"list\\").getValue();
-  const draw_data = globals.previousScope.variables.get(\\"draw_data\\").getValue();
-  const display_list = globals.previousScope.variables.get(\\"display_list\\").getValue();
-  const set_head = globals.previousScope.variables.get(\\"set_head\\").getValue();
-  const set_tail = globals.previousScope.variables.get(\\"set_tail\\").getValue();
-  const array_length = globals.previousScope.variables.get(\\"array_length\\").getValue();
-  const is_array = globals.previousScope.variables.get(\\"is_array\\").getValue();
-  const stream_tail = globals.previousScope.variables.get(\\"stream_tail\\").getValue();
-  const stream = globals.previousScope.variables.get(\\"stream\\").getValue();
-  const list_to_stream = globals.previousScope.variables.get(\\"list_to_stream\\").getValue();
-  const parse = globals.previousScope.variables.get(\\"parse\\").getValue();
-  const apply_in_underlying_javascript = globals.previousScope.variables.get(\\"apply_in_underlying_javascript\\").getValue();
+"{
+  const get_time = nativeStorage.builtins.get(\\"get_time\\");
+  const display = nativeStorage.builtins.get(\\"display\\");
+  const raw_display = nativeStorage.builtins.get(\\"raw_display\\");
+  const stringify = nativeStorage.builtins.get(\\"stringify\\");
+  const error = nativeStorage.builtins.get(\\"error\\");
+  const prompt = nativeStorage.builtins.get(\\"prompt\\");
+  const is_number = nativeStorage.builtins.get(\\"is_number\\");
+  const is_string = nativeStorage.builtins.get(\\"is_string\\");
+  const is_function = nativeStorage.builtins.get(\\"is_function\\");
+  const is_boolean = nativeStorage.builtins.get(\\"is_boolean\\");
+  const is_undefined = nativeStorage.builtins.get(\\"is_undefined\\");
+  const parse_int = nativeStorage.builtins.get(\\"parse_int\\");
+  const char_at = nativeStorage.builtins.get(\\"char_at\\");
+  const undefined = nativeStorage.builtins.get(\\"undefined\\");
+  const NaN = nativeStorage.builtins.get(\\"NaN\\");
+  const Infinity = nativeStorage.builtins.get(\\"Infinity\\");
+  const math_abs = nativeStorage.builtins.get(\\"math_abs\\");
+  const math_acos = nativeStorage.builtins.get(\\"math_acos\\");
+  const math_acosh = nativeStorage.builtins.get(\\"math_acosh\\");
+  const math_asin = nativeStorage.builtins.get(\\"math_asin\\");
+  const math_asinh = nativeStorage.builtins.get(\\"math_asinh\\");
+  const math_atan = nativeStorage.builtins.get(\\"math_atan\\");
+  const math_atanh = nativeStorage.builtins.get(\\"math_atanh\\");
+  const math_atan2 = nativeStorage.builtins.get(\\"math_atan2\\");
+  const math_ceil = nativeStorage.builtins.get(\\"math_ceil\\");
+  const math_cbrt = nativeStorage.builtins.get(\\"math_cbrt\\");
+  const math_expm1 = nativeStorage.builtins.get(\\"math_expm1\\");
+  const math_clz32 = nativeStorage.builtins.get(\\"math_clz32\\");
+  const math_cos = nativeStorage.builtins.get(\\"math_cos\\");
+  const math_cosh = nativeStorage.builtins.get(\\"math_cosh\\");
+  const math_exp = nativeStorage.builtins.get(\\"math_exp\\");
+  const math_floor = nativeStorage.builtins.get(\\"math_floor\\");
+  const math_fround = nativeStorage.builtins.get(\\"math_fround\\");
+  const math_hypot = nativeStorage.builtins.get(\\"math_hypot\\");
+  const math_imul = nativeStorage.builtins.get(\\"math_imul\\");
+  const math_log = nativeStorage.builtins.get(\\"math_log\\");
+  const math_log1p = nativeStorage.builtins.get(\\"math_log1p\\");
+  const math_log2 = nativeStorage.builtins.get(\\"math_log2\\");
+  const math_log10 = nativeStorage.builtins.get(\\"math_log10\\");
+  const math_max = nativeStorage.builtins.get(\\"math_max\\");
+  const math_min = nativeStorage.builtins.get(\\"math_min\\");
+  const math_pow = nativeStorage.builtins.get(\\"math_pow\\");
+  const math_random = nativeStorage.builtins.get(\\"math_random\\");
+  const math_round = nativeStorage.builtins.get(\\"math_round\\");
+  const math_sign = nativeStorage.builtins.get(\\"math_sign\\");
+  const math_sin = nativeStorage.builtins.get(\\"math_sin\\");
+  const math_sinh = nativeStorage.builtins.get(\\"math_sinh\\");
+  const math_sqrt = nativeStorage.builtins.get(\\"math_sqrt\\");
+  const math_tan = nativeStorage.builtins.get(\\"math_tan\\");
+  const math_tanh = nativeStorage.builtins.get(\\"math_tanh\\");
+  const math_trunc = nativeStorage.builtins.get(\\"math_trunc\\");
+  const math_E = nativeStorage.builtins.get(\\"math_E\\");
+  const math_LN10 = nativeStorage.builtins.get(\\"math_LN10\\");
+  const math_LN2 = nativeStorage.builtins.get(\\"math_LN2\\");
+  const math_LOG10E = nativeStorage.builtins.get(\\"math_LOG10E\\");
+  const math_LOG2E = nativeStorage.builtins.get(\\"math_LOG2E\\");
+  const math_PI = nativeStorage.builtins.get(\\"math_PI\\");
+  const math_SQRT1_2 = nativeStorage.builtins.get(\\"math_SQRT1_2\\");
+  const math_SQRT2 = nativeStorage.builtins.get(\\"math_SQRT2\\");
+  const pair = nativeStorage.builtins.get(\\"pair\\");
+  const is_pair = nativeStorage.builtins.get(\\"is_pair\\");
+  const head = nativeStorage.builtins.get(\\"head\\");
+  const tail = nativeStorage.builtins.get(\\"tail\\");
+  const is_null = nativeStorage.builtins.get(\\"is_null\\");
+  const list = nativeStorage.builtins.get(\\"list\\");
+  const draw_data = nativeStorage.builtins.get(\\"draw_data\\");
+  const display_list = nativeStorage.builtins.get(\\"display_list\\");
+  const set_head = nativeStorage.builtins.get(\\"set_head\\");
+  const set_tail = nativeStorage.builtins.get(\\"set_tail\\");
+  const array_length = nativeStorage.builtins.get(\\"array_length\\");
+  const is_array = nativeStorage.builtins.get(\\"is_array\\");
+  const stream_tail = nativeStorage.builtins.get(\\"stream_tail\\");
+  const stream = nativeStorage.builtins.get(\\"stream\\");
+  const list_to_stream = nativeStorage.builtins.get(\\"list_to_stream\\");
+  const parse = nativeStorage.builtins.get(\\"parse\\");
+  const apply_in_underlying_javascript = nativeStorage.builtins.get(\\"apply_in_underlying_javascript\\");
   {
+    const native0 = nativeStorage;
+    const callIfFuncAndRightArgs0 = native0.operators.get(\\"callIfFuncAndRightArgs\\");
+    const boolOrErr0 = native0.operators.get(\\"boolOrErr\\");
+    const wrap90 = native0.operators.get(\\"wrap\\");
+    const unaryOp = native0.operators.get(\\"unaryOp\\");
+    const binaryOp = native0.operators.get(\\"binaryOp\\");
+    const throwIfTimeout = native0.operators.get(\\"throwIfTimeout\\");
+    const setProp = native0.operators.get(\\"setProp\\");
+    const getProp = native0.operators.get(\\"getProp\\");
+    const builtins = native0.operators.get(\\"builtins\\");
+    native0.evaller = program => eval(program);
+    undefined;
     const boolOrErr = 1;
     setProp(boolOrErr, 123, 1, 2, 0);
     const f = wrap90((callIfFuncAndRightArgs, wrap0, wrap1, wrap2, wrap3, wrap4, wrap5, wrap6, wrap7, wrap8, wrap9) => {
@@ -106,126 +107,107 @@ const globals = native0.globals;
       wrap9;
     }, \\"function f(callIfFuncAndRightArgs, wrap0, wrap1, wrap2, wrap3, wrap4, wrap5, wrap6, wrap7, wrap8, wrap9) {\\\\n  let wrap = 2;\\\\n  wrap0;\\\\n  wrap1;\\\\n  wrap2;\\\\n  wrap3;\\\\n  wrap4;\\\\n  wrap5;\\\\n  wrap6;\\\\n  wrap7;\\\\n  wrap8;\\\\n  wrap9;\\\\n}\\", native0);
     const native = 123;
-    globals.variables.set(\\"boolOrErr\\", {
-      kind: \\"const\\",
-      getValue: () => {
-        return boolOrErr;
-      }
-    });
-    globals.variables.set(\\"f\\", {
-      kind: \\"const\\",
-      getValue: () => {
-        return f;
-      }
-    });
-    globals.variables.set(\\"native\\", {
-      kind: \\"const\\",
-      getValue: () => {
-        return native;
-      }
-    });
   }
 }
-lastStatementResult;
 "
 `;
 
 exports[`builtins do get prepended 1`] = `
 Object {
   "code": "\\"ensure_builtins\\";",
-  "transpiled": "const native = nativeStorage;
-const callIfFuncAndRightArgs = native.operators.get(\\"callIfFuncAndRightArgs\\");
-const boolOrErr = native.operators.get(\\"boolOrErr\\");
-const wrap = native.operators.get(\\"wrap\\");
-const unaryOp = native.operators.get(\\"unaryOp\\");
-const binaryOp = native.operators.get(\\"binaryOp\\");
-const throwIfTimeout = native.operators.get(\\"throwIfTimeout\\");
-const setProp = native.operators.get(\\"setProp\\");
-const getProp = native.operators.get(\\"getProp\\");
-let lastStatementResult = undefined;
-const globals = native.globals;
-{
-  const get_time = globals.previousScope.variables.get(\\"get_time\\").getValue();
-  const display = globals.previousScope.variables.get(\\"display\\").getValue();
-  const raw_display = globals.previousScope.variables.get(\\"raw_display\\").getValue();
-  const stringify = globals.previousScope.variables.get(\\"stringify\\").getValue();
-  const error = globals.previousScope.variables.get(\\"error\\").getValue();
-  const prompt = globals.previousScope.variables.get(\\"prompt\\").getValue();
-  const is_number = globals.previousScope.variables.get(\\"is_number\\").getValue();
-  const is_string = globals.previousScope.variables.get(\\"is_string\\").getValue();
-  const is_function = globals.previousScope.variables.get(\\"is_function\\").getValue();
-  const is_boolean = globals.previousScope.variables.get(\\"is_boolean\\").getValue();
-  const is_undefined = globals.previousScope.variables.get(\\"is_undefined\\").getValue();
-  const parse_int = globals.previousScope.variables.get(\\"parse_int\\").getValue();
-  const char_at = globals.previousScope.variables.get(\\"char_at\\").getValue();
-  const undefined = globals.previousScope.variables.get(\\"undefined\\").getValue();
-  const NaN = globals.previousScope.variables.get(\\"NaN\\").getValue();
-  const Infinity = globals.previousScope.variables.get(\\"Infinity\\").getValue();
-  const math_abs = globals.previousScope.variables.get(\\"math_abs\\").getValue();
-  const math_acos = globals.previousScope.variables.get(\\"math_acos\\").getValue();
-  const math_acosh = globals.previousScope.variables.get(\\"math_acosh\\").getValue();
-  const math_asin = globals.previousScope.variables.get(\\"math_asin\\").getValue();
-  const math_asinh = globals.previousScope.variables.get(\\"math_asinh\\").getValue();
-  const math_atan = globals.previousScope.variables.get(\\"math_atan\\").getValue();
-  const math_atanh = globals.previousScope.variables.get(\\"math_atanh\\").getValue();
-  const math_atan2 = globals.previousScope.variables.get(\\"math_atan2\\").getValue();
-  const math_ceil = globals.previousScope.variables.get(\\"math_ceil\\").getValue();
-  const math_cbrt = globals.previousScope.variables.get(\\"math_cbrt\\").getValue();
-  const math_expm1 = globals.previousScope.variables.get(\\"math_expm1\\").getValue();
-  const math_clz32 = globals.previousScope.variables.get(\\"math_clz32\\").getValue();
-  const math_cos = globals.previousScope.variables.get(\\"math_cos\\").getValue();
-  const math_cosh = globals.previousScope.variables.get(\\"math_cosh\\").getValue();
-  const math_exp = globals.previousScope.variables.get(\\"math_exp\\").getValue();
-  const math_floor = globals.previousScope.variables.get(\\"math_floor\\").getValue();
-  const math_fround = globals.previousScope.variables.get(\\"math_fround\\").getValue();
-  const math_hypot = globals.previousScope.variables.get(\\"math_hypot\\").getValue();
-  const math_imul = globals.previousScope.variables.get(\\"math_imul\\").getValue();
-  const math_log = globals.previousScope.variables.get(\\"math_log\\").getValue();
-  const math_log1p = globals.previousScope.variables.get(\\"math_log1p\\").getValue();
-  const math_log2 = globals.previousScope.variables.get(\\"math_log2\\").getValue();
-  const math_log10 = globals.previousScope.variables.get(\\"math_log10\\").getValue();
-  const math_max = globals.previousScope.variables.get(\\"math_max\\").getValue();
-  const math_min = globals.previousScope.variables.get(\\"math_min\\").getValue();
-  const math_pow = globals.previousScope.variables.get(\\"math_pow\\").getValue();
-  const math_random = globals.previousScope.variables.get(\\"math_random\\").getValue();
-  const math_round = globals.previousScope.variables.get(\\"math_round\\").getValue();
-  const math_sign = globals.previousScope.variables.get(\\"math_sign\\").getValue();
-  const math_sin = globals.previousScope.variables.get(\\"math_sin\\").getValue();
-  const math_sinh = globals.previousScope.variables.get(\\"math_sinh\\").getValue();
-  const math_sqrt = globals.previousScope.variables.get(\\"math_sqrt\\").getValue();
-  const math_tan = globals.previousScope.variables.get(\\"math_tan\\").getValue();
-  const math_tanh = globals.previousScope.variables.get(\\"math_tanh\\").getValue();
-  const math_trunc = globals.previousScope.variables.get(\\"math_trunc\\").getValue();
-  const math_E = globals.previousScope.variables.get(\\"math_E\\").getValue();
-  const math_LN10 = globals.previousScope.variables.get(\\"math_LN10\\").getValue();
-  const math_LN2 = globals.previousScope.variables.get(\\"math_LN2\\").getValue();
-  const math_LOG10E = globals.previousScope.variables.get(\\"math_LOG10E\\").getValue();
-  const math_LOG2E = globals.previousScope.variables.get(\\"math_LOG2E\\").getValue();
-  const math_PI = globals.previousScope.variables.get(\\"math_PI\\").getValue();
-  const math_SQRT1_2 = globals.previousScope.variables.get(\\"math_SQRT1_2\\").getValue();
-  const math_SQRT2 = globals.previousScope.variables.get(\\"math_SQRT2\\").getValue();
-  const pair = globals.previousScope.variables.get(\\"pair\\").getValue();
-  const is_pair = globals.previousScope.variables.get(\\"is_pair\\").getValue();
-  const head = globals.previousScope.variables.get(\\"head\\").getValue();
-  const tail = globals.previousScope.variables.get(\\"tail\\").getValue();
-  const is_null = globals.previousScope.variables.get(\\"is_null\\").getValue();
-  const list = globals.previousScope.variables.get(\\"list\\").getValue();
-  const draw_data = globals.previousScope.variables.get(\\"draw_data\\").getValue();
-  const display_list = globals.previousScope.variables.get(\\"display_list\\").getValue();
-  const set_head = globals.previousScope.variables.get(\\"set_head\\").getValue();
-  const set_tail = globals.previousScope.variables.get(\\"set_tail\\").getValue();
-  const array_length = globals.previousScope.variables.get(\\"array_length\\").getValue();
-  const is_array = globals.previousScope.variables.get(\\"is_array\\").getValue();
-  const stream_tail = globals.previousScope.variables.get(\\"stream_tail\\").getValue();
-  const stream = globals.previousScope.variables.get(\\"stream\\").getValue();
-  const list_to_stream = globals.previousScope.variables.get(\\"list_to_stream\\").getValue();
-  const parse = globals.previousScope.variables.get(\\"parse\\").getValue();
-  const apply_in_underlying_javascript = globals.previousScope.variables.get(\\"apply_in_underlying_javascript\\").getValue();
+  "transpiled": "{
+  const get_time = nativeStorage.builtins.get(\\"get_time\\");
+  const display = nativeStorage.builtins.get(\\"display\\");
+  const raw_display = nativeStorage.builtins.get(\\"raw_display\\");
+  const stringify = nativeStorage.builtins.get(\\"stringify\\");
+  const error = nativeStorage.builtins.get(\\"error\\");
+  const prompt = nativeStorage.builtins.get(\\"prompt\\");
+  const is_number = nativeStorage.builtins.get(\\"is_number\\");
+  const is_string = nativeStorage.builtins.get(\\"is_string\\");
+  const is_function = nativeStorage.builtins.get(\\"is_function\\");
+  const is_boolean = nativeStorage.builtins.get(\\"is_boolean\\");
+  const is_undefined = nativeStorage.builtins.get(\\"is_undefined\\");
+  const parse_int = nativeStorage.builtins.get(\\"parse_int\\");
+  const char_at = nativeStorage.builtins.get(\\"char_at\\");
+  const undefined = nativeStorage.builtins.get(\\"undefined\\");
+  const NaN = nativeStorage.builtins.get(\\"NaN\\");
+  const Infinity = nativeStorage.builtins.get(\\"Infinity\\");
+  const math_abs = nativeStorage.builtins.get(\\"math_abs\\");
+  const math_acos = nativeStorage.builtins.get(\\"math_acos\\");
+  const math_acosh = nativeStorage.builtins.get(\\"math_acosh\\");
+  const math_asin = nativeStorage.builtins.get(\\"math_asin\\");
+  const math_asinh = nativeStorage.builtins.get(\\"math_asinh\\");
+  const math_atan = nativeStorage.builtins.get(\\"math_atan\\");
+  const math_atanh = nativeStorage.builtins.get(\\"math_atanh\\");
+  const math_atan2 = nativeStorage.builtins.get(\\"math_atan2\\");
+  const math_ceil = nativeStorage.builtins.get(\\"math_ceil\\");
+  const math_cbrt = nativeStorage.builtins.get(\\"math_cbrt\\");
+  const math_expm1 = nativeStorage.builtins.get(\\"math_expm1\\");
+  const math_clz32 = nativeStorage.builtins.get(\\"math_clz32\\");
+  const math_cos = nativeStorage.builtins.get(\\"math_cos\\");
+  const math_cosh = nativeStorage.builtins.get(\\"math_cosh\\");
+  const math_exp = nativeStorage.builtins.get(\\"math_exp\\");
+  const math_floor = nativeStorage.builtins.get(\\"math_floor\\");
+  const math_fround = nativeStorage.builtins.get(\\"math_fround\\");
+  const math_hypot = nativeStorage.builtins.get(\\"math_hypot\\");
+  const math_imul = nativeStorage.builtins.get(\\"math_imul\\");
+  const math_log = nativeStorage.builtins.get(\\"math_log\\");
+  const math_log1p = nativeStorage.builtins.get(\\"math_log1p\\");
+  const math_log2 = nativeStorage.builtins.get(\\"math_log2\\");
+  const math_log10 = nativeStorage.builtins.get(\\"math_log10\\");
+  const math_max = nativeStorage.builtins.get(\\"math_max\\");
+  const math_min = nativeStorage.builtins.get(\\"math_min\\");
+  const math_pow = nativeStorage.builtins.get(\\"math_pow\\");
+  const math_random = nativeStorage.builtins.get(\\"math_random\\");
+  const math_round = nativeStorage.builtins.get(\\"math_round\\");
+  const math_sign = nativeStorage.builtins.get(\\"math_sign\\");
+  const math_sin = nativeStorage.builtins.get(\\"math_sin\\");
+  const math_sinh = nativeStorage.builtins.get(\\"math_sinh\\");
+  const math_sqrt = nativeStorage.builtins.get(\\"math_sqrt\\");
+  const math_tan = nativeStorage.builtins.get(\\"math_tan\\");
+  const math_tanh = nativeStorage.builtins.get(\\"math_tanh\\");
+  const math_trunc = nativeStorage.builtins.get(\\"math_trunc\\");
+  const math_E = nativeStorage.builtins.get(\\"math_E\\");
+  const math_LN10 = nativeStorage.builtins.get(\\"math_LN10\\");
+  const math_LN2 = nativeStorage.builtins.get(\\"math_LN2\\");
+  const math_LOG10E = nativeStorage.builtins.get(\\"math_LOG10E\\");
+  const math_LOG2E = nativeStorage.builtins.get(\\"math_LOG2E\\");
+  const math_PI = nativeStorage.builtins.get(\\"math_PI\\");
+  const math_SQRT1_2 = nativeStorage.builtins.get(\\"math_SQRT1_2\\");
+  const math_SQRT2 = nativeStorage.builtins.get(\\"math_SQRT2\\");
+  const pair = nativeStorage.builtins.get(\\"pair\\");
+  const is_pair = nativeStorage.builtins.get(\\"is_pair\\");
+  const head = nativeStorage.builtins.get(\\"head\\");
+  const tail = nativeStorage.builtins.get(\\"tail\\");
+  const is_null = nativeStorage.builtins.get(\\"is_null\\");
+  const list = nativeStorage.builtins.get(\\"list\\");
+  const draw_data = nativeStorage.builtins.get(\\"draw_data\\");
+  const display_list = nativeStorage.builtins.get(\\"display_list\\");
+  const set_head = nativeStorage.builtins.get(\\"set_head\\");
+  const set_tail = nativeStorage.builtins.get(\\"set_tail\\");
+  const array_length = nativeStorage.builtins.get(\\"array_length\\");
+  const is_array = nativeStorage.builtins.get(\\"is_array\\");
+  const stream_tail = nativeStorage.builtins.get(\\"stream_tail\\");
+  const stream = nativeStorage.builtins.get(\\"stream\\");
+  const list_to_stream = nativeStorage.builtins.get(\\"list_to_stream\\");
+  const parse = nativeStorage.builtins.get(\\"parse\\");
+  const apply_in_underlying_javascript = nativeStorage.builtins.get(\\"apply_in_underlying_javascript\\");
   {
-    lastStatementResult = eval(\\"\\\\\\"ensure_builtins\\\\\\";\\");
+    const native = nativeStorage;
+    const callIfFuncAndRightArgs = native.operators.get(\\"callIfFuncAndRightArgs\\");
+    const boolOrErr = native.operators.get(\\"boolOrErr\\");
+    const wrap = native.operators.get(\\"wrap\\");
+    const unaryOp = native.operators.get(\\"unaryOp\\");
+    const binaryOp = native.operators.get(\\"binaryOp\\");
+    const throwIfTimeout = native.operators.get(\\"throwIfTimeout\\");
+    const setProp = native.operators.get(\\"setProp\\");
+    const getProp = native.operators.get(\\"getProp\\");
+    const builtins = native.operators.get(\\"builtins\\");
+    native.evaller = program => eval(program);
+    undefined;
+    \\"ensure_builtins\\";
   }
 }
-lastStatementResult;
 ",
 }
 `;
diff --git a/src/transpiler/evalContainer.ts b/src/transpiler/evalContainer.ts
index 81484bd67..627ce776f 100644
--- a/src/transpiler/evalContainer.ts
+++ b/src/transpiler/evalContainer.ts
@@ -13,6 +13,10 @@ export const sandboxedEval: Evaler = new Function(
   NATIVE_STORAGE_ID,
   MODULE_PARAMS_ID,
   `
-return eval(code)
+  if (${NATIVE_STORAGE_ID}.evaller === null) {
+    return eval(code);
+  } else {
+    return ${NATIVE_STORAGE_ID}.evaller(code);
+  }
 `
 ) as Evaler
diff --git a/src/transpiler/transpiler.ts b/src/transpiler/transpiler.ts
index a6ee75781..44e65aca8 100644
--- a/src/transpiler/transpiler.ts
+++ b/src/transpiler/transpiler.ts
@@ -1,9 +1,9 @@
 import { ancestor, simple } from '../utils/walkers'
 import { generate } from 'astring'
 import * as es from 'estree'
-import { RawSourceMap, SourceMapGenerator } from 'source-map'
-import { AllowedDeclarations, Context, NativeStorage, ValueWrapper } from '../types'
-import { ConstAssignment, UndefinedVariable } from '../errors/errors'
+import { SourceMapGenerator } from 'source-map'
+import { AllowedDeclarations, Context, NativeStorage } from '../types'
+import { UndefinedVariable } from '../errors/errors'
 import { memoizedGetModuleFile } from '../modules/moduleLoader'
 import * as create from '../utils/astCreator'
 import {
@@ -29,8 +29,7 @@ const globalIdNames = [
   'throwIfTimeout',
   'setProp',
   'getProp',
-  'lastStatementResult',
-  'globals'
+  'builtins'
 ] as const
 
 export type NativeIds = Record<typeof globalIdNames[number], es.Identifier>
@@ -96,79 +95,7 @@ export function transformImportDeclarations(program: es.Program) {
   program.body = (result as (es.Statement | es.ModuleDeclaration)[]).concat(program.body)
 }
 
-function createStatementAstToStoreBackCurrentlyDeclaredGlobal(
-  name: string,
-  kind: AllowedDeclarations,
-  globalIds: NativeIds,
-  usedIdentifiers: Set<string>
-): es.ExpressionStatement {
-  const paramName = create.identifier(getUniqueId(usedIdentifiers))
-  const variableIdentifier = create.identifier(name)
-  const properties = [
-    create.property('kind', create.literal(kind)),
-    create.property(
-      'getValue',
-      create.blockArrowFunction([], [create.returnStatement(variableIdentifier)])
-    )
-  ]
-  if (kind === 'let') {
-    properties.push(
-      create.property(
-        'assignNewValue',
-        create.functionExpression(
-          [paramName],
-          [create.returnStatement(create.assignmentExpression(variableIdentifier, paramName))]
-        )
-      )
-    )
-  }
-  return create.expressionStatement(
-    create.callExpression(
-      create.memberExpression(create.memberExpression(globalIds.globals, 'variables'), 'set'),
-      [create.literal(name), create.objectExpression(properties)]
-    )
-  )
-}
-
-function wrapWithPreviouslyDeclaredGlobals(
-  statements: es.Statement[],
-  nativeStorage: NativeStorage,
-  globalIds: NativeIds
-) {
-  let currentVariableScope = nativeStorage.globals!.previousScope
-  let timesToGoUp = 1
-  let wrapped = create.blockStatement(statements)
-  while (currentVariableScope !== null) {
-    const initialisingStatements: es.Statement[] = []
-    currentVariableScope.variables.forEach(({ kind }: ValueWrapper, name: string) => {
-      let unwrappedValueAst: es.Expression = globalIds.globals
-      for (let i = 0; i < timesToGoUp; i += 1) {
-        unwrappedValueAst = create.memberExpression(unwrappedValueAst, 'previousScope')
-      }
-      unwrappedValueAst = create.callExpression(
-        create.memberExpression(
-          create.callExpression(
-            create.memberExpression(create.memberExpression(unwrappedValueAst, 'variables'), 'get'),
-            [create.literal(name)]
-          ),
-          'getValue'
-        ),
-        []
-      )
-      initialisingStatements.push(create.declaration(name, kind, unwrappedValueAst))
-    })
-    timesToGoUp += 1
-    currentVariableScope = currentVariableScope.previousScope
-    wrapped = create.blockStatement([...initialisingStatements, wrapped])
-  }
-  return wrapped
-}
-
-function createStatementsToStoreCurrentlyDeclaredGlobals(
-  program: es.Program,
-  globalIds: NativeIds,
-  usedIdentifiers: Set<string>
-) {
+function getGloballyDeclaredIdentifiers(program: es.Program): string[] {
   return program.body
     .filter(statement => statement.type === 'VariableDeclaration')
     .map(
@@ -177,13 +104,7 @@ function createStatementsToStoreCurrentlyDeclaredGlobals(
           0: { id }
         },
         kind
-      }: es.VariableDeclaration) =>
-        createStatementAstToStoreBackCurrentlyDeclaredGlobal(
-          (id as es.Identifier).name,
-          kind as AllowedDeclarations,
-          globalIds,
-          usedIdentifiers
-        )
+      }: es.VariableDeclaration) => (id as es.Identifier).name
     )
 }
 
@@ -337,46 +258,13 @@ function transformCallExpressionsToCheckIfFunction(program: es.Program, globalId
   })
 }
 
-export function checkForUndefinedVariablesAndTransformAssignmentsToPropagateBackNewValue(
+export function checkForUndefinedVariables(
   program: es.Program,
-  skipErrors = false,
   nativeStorage: NativeStorage,
-  globalIds: NativeIds
+  globalIds: NativeIds,
+  skipUndefined: boolean
 ) {
-  const globalEnvironment = nativeStorage.globals
-  const previousVariablesToAst = new Map<
-    string,
-    { isConstant: boolean; variableLocationId: es.Expression }
-  >()
-  let variableScope = globalEnvironment
-  let variableScopeId: es.Expression = globalIds.globals
-  while (variableScope !== null) {
-    for (const [name, { kind }] of variableScope.variables) {
-      if (!previousVariablesToAst.has(name)) {
-        previousVariablesToAst.set(name, {
-          isConstant: kind === 'const',
-          variableLocationId: create.callExpression(
-            create.memberExpression(create.memberExpression(variableScopeId, 'variables'), 'get'),
-            [create.literal(name)]
-          )
-        })
-      }
-    }
-    variableScope = variableScope.previousScope
-    variableScopeId = create.memberExpression(variableScopeId, 'previousScope')
-  }
-  for (const node of program.body) {
-    if (node.type !== 'ImportDeclaration') {
-      break
-    }
-    const symbols = node.specifiers.map(specifier => specifier.local.name)
-    for (const symbol of symbols) {
-      previousVariablesToAst.set(symbol, {
-        isConstant: true,
-        variableLocationId: create.literal(-1)
-      })
-    }
-  }
+  const builtins = nativeStorage.builtins
   const identifiersIntroducedByNode = new Map<es.Node, Set<string>>()
   function processBlock(node: es.Program | es.BlockStatement) {
     const identifiers = new Set<string>()
@@ -391,7 +279,7 @@ export function checkForUndefinedVariablesAndTransformAssignmentsToPropagateBack
   }
   function processFunction(
     node: es.FunctionDeclaration | es.ArrowFunctionExpression,
-    ancestors: es.Node[]
+    _ancestors: es.Node[]
   ) {
     identifiersIntroducedByNode.set(
       node,
@@ -431,74 +319,20 @@ export function checkForUndefinedVariablesAndTransformAssignmentsToPropagateBack
   for (const [identifier, ancestors] of identifiersToAncestors) {
     const name = identifier.name
     const isCurrentlyDeclared = ancestors.some(a => identifiersIntroducedByNode.get(a)?.has(name))
-    if (!isCurrentlyDeclared) {
-      if (previousVariablesToAst.has(name)) {
-        const lastAncestor: es.Node = ancestors[ancestors.length - 2]
-        const { isConstant, variableLocationId } = previousVariablesToAst.get(name)!
-        if (lastAncestor.type === 'AssignmentExpression' && lastAncestor.left === identifier) {
-          // if this is an assignment expression, we want to propagate back the change
-          if (isConstant) {
-            throw new ConstAssignment(identifier, name)
-          } else {
-            lastAncestor.right = create.callExpression(
-              create.memberExpression(variableLocationId, 'assignNewValue'),
-              [lastAncestor.right]
-            )
-          }
-        } else {
-          /**
-           * if this is not the left side of an assignment expression, we need to replace this with
-           * the actual value stored in the correct scope, as calling functions defined in a
-           * previous block might have side effects that change the variable.
-           * e.g.
-           * // first eval:
-           * let counter = 0;
-           * function f() {
-           *   counter = counter + 1;
-           * }
-           * becomes
-           * let counter = 0;
-           * function f() {
-           *   counter = counter + 1;
-           * }
-           * variables.set("counter", getValue: ()=>counter, assignNewValue: newValue => counter = newValue);
-           * // second eval (wrong):
-           * f(); counter;
-           * becomes
-           * let counter = variables.get("counter").getValue(); // set back counter;
-           * {
-           *   f(); // this has a side effect of incrementing counter
-           *   return counter; // that does not get propagated here
-           * }
-           * // second eval (fixed):
-           * f(); counter;
-           * becomes
-           * let counter = variables.get("counter").getValue(); // set back counter;
-           * {
-           *   f(); // this has a side effect of incrementing counter
-           *   return (counter = variables.get("counter").getValue()); // we have no choice but to
-           *    // always assume that counter is updated through a side effect and always retrieve its
-           *    // real value
-           * }
-           */
-          if (!isConstant) {
-            // if it is a constant, it will definitely not mutate so above change is not needed
-            const toExpression: es.AssignmentExpression =
-              identifier as unknown as es.AssignmentExpression
-            toExpression.type = 'AssignmentExpression'
-            toExpression.operator = '='
-            toExpression.left = create.identifier(name)
-            toExpression.right = create.callExpression(
-              create.memberExpression(variableLocationId, 'getValue'),
-              []
-            )
-          }
-        }
-      } else if (!nativeInternalNames.has(name)) {
-        if (!skipErrors) {
-          throw new UndefinedVariable(name, identifier)
-        }
-      }
+    if (isCurrentlyDeclared) {
+      continue
+    }
+    const isPreviouslyDeclared = nativeStorage.previousProgramsIdentifiers.has(name)
+    if (isPreviouslyDeclared) {
+      continue
+    }
+    const isBuiltin = builtins.has(name)
+    if (isBuiltin) {
+      continue
+    }
+    const isNativeId = nativeInternalNames.has(name)
+    if (!isNativeId && !skipUndefined) {
+      throw new UndefinedVariable(name, identifier)
     }
   }
 }
@@ -538,55 +372,6 @@ function getNativeIds(program: es.Program, usedIdentifiers: Set<string>): Native
   return globalIds as NativeIds
 }
 
-/**
- * statement1;
- * statement2;
- * ...
- * const a = 1; //lastStatement example 1 (should give undefined)
- * 1 + 1; //lastStatement example 2 (should give 2)
- * b = fun(5); //lastStatement example 3 (should set b to fun(5))
- * if (true) { true; } else { false; } //lastStatement example 4 (should give true)
- * for (let i = 0; i < 5; i = i + 1) { i; } //lastStatement example 5 (should give 4)
- *
- * We want to preserve the last evaluated statement's result to return back, so
- * for const/let declarations we simply don't change anything, and return undefined
- * at the end.
- *
- * For others, we will convert it into a string, wrap it in an eval, and store
- * the result in a temporary variable. e.g.
- *
- * const tempVar = eval("1+1;");
- * const tempVar = eval("if (true) { true; } else { false; }");
- * etc etc...
- * now at the end of all the appended statements we can do
- * return tempVar;
- */
-
-function splitLastStatementIntoStorageOfResultAndAccessorPair(
-  lastStatement: es.Statement,
-  globalIds: NativeIds
-): { lastStatementStoredInResult: es.Statement; evalMap?: RawSourceMap } {
-  if (lastStatement.type === 'VariableDeclaration') {
-    return {
-      lastStatementStoredInResult: lastStatement
-    }
-  }
-  const map = new SourceMapGenerator({ file: 'lastline' })
-  const lastStatementAsCode = generate(lastStatement, { lineEnd: ' ', sourceMap: map, version: 3 })
-  const uniqueDeclarationToStoreLastStatementResult = create.expressionStatement(
-    create.assignmentExpression(
-      globalIds.lastStatementResult,
-      create.callExpression(create.identifier('eval'), [
-        create.literal(lastStatementAsCode, lastStatement.loc!)
-      ])
-    )
-  )
-  return {
-    lastStatementStoredInResult: uniqueDeclarationToStoreLastStatementResult,
-    evalMap: map.toJSON()
-  }
-}
-
 function transformUnaryAndBinaryOperationsToFunctionCalls(
   program: es.Program,
   globalIds: NativeIds,
@@ -694,20 +479,46 @@ function addInfiniteLoopProtection(
   })
 }
 
-export function transpile(
-  program: es.Program,
-  context: Context,
-  skipUndefinedVariableErrors = false
+function evallerReplacer(globalIds: NativeIds): es.ExpressionStatement {
+  const arg = create.identifier('program')
+  return create.expressionStatement(
+    create.assignmentExpression(
+      create.memberExpression(globalIds.native, 'evaller'),
+      create.arrowFunctionExpression([arg], create.callExpression(create.identifier('eval'), [arg]))
+    )
+  )
+}
+
+function wrapWithBuiltins(
+  statements: es.Statement[],
+  nativeStorage: NativeStorage,
+  globalIds: NativeIds
 ) {
+  const initialisingStatements: es.Statement[] = []
+  nativeStorage.builtins.forEach((_unused, name: string) => {
+    initialisingStatements.push(
+      create.declaration(
+        name,
+        'const',
+        create.callExpression(
+          create.memberExpression(
+            create.memberExpression(create.identifier(NATIVE_STORAGE_ID), 'builtins'),
+            'get'
+          ),
+          [create.literal(name)]
+        )
+      )
+    )
+  })
+  return create.blockStatement([...initialisingStatements, create.blockStatement(statements)])
+}
+
+export function transpile(program: es.Program, context: Context, skipUndefined = false) {
   const usedIdentifiers = new Set<string>([
     ...getIdentifiersInProgram(program),
     ...getIdentifiersInNativeStorage(context.nativeStorage)
   ])
   const globalIds = getNativeIds(program, usedIdentifiers)
-  context.nativeStorage.globals = {
-    variables: new Map(),
-    previousScope: context.nativeStorage.globals
-  }
   if (program.body.length === 0) {
     return { transpiled: '' }
   }
@@ -720,43 +531,33 @@ export function transpile(
   transformSomeExpressionsToCheckIfBoolean(program, globalIds)
   transformPropertyAssignment(program, globalIds)
   transformPropertyAccess(program, globalIds)
-  checkForUndefinedVariablesAndTransformAssignmentsToPropagateBackNewValue(
-    program,
-    skipUndefinedVariableErrors,
-    context.nativeStorage,
-    globalIds
-  )
+  checkForUndefinedVariables(program, context.nativeStorage, globalIds, skipUndefined)
   transformFunctionDeclarationsToArrowFunctions(program, functionsToStringMap)
   wrapArrowFunctionsToAllowNormalCallsAndNiceToString(program, functionsToStringMap, globalIds)
   addInfiniteLoopProtection(program, globalIds, usedIdentifiers)
 
   const modulePrefix = prefixModule(program)
   transformImportDeclarations(program)
-  const statementsToSaveDeclaredGlobals = createStatementsToStoreCurrentlyDeclaredGlobals(
-    program,
-    globalIds,
-    usedIdentifiers
+  getGloballyDeclaredIdentifiers(program).forEach(id =>
+    context.nativeStorage.previousProgramsIdentifiers.add(id)
   )
   const statements = program.body as es.Statement[]
-  const lastStatement = statements.pop() as es.Statement
-  const { lastStatementStoredInResult, evalMap } =
-    splitLastStatementIntoStorageOfResultAndAccessorPair(lastStatement, globalIds)
-
-  const body = [
-    wrapWithPreviouslyDeclaredGlobals(
-      [...statements, lastStatementStoredInResult, ...statementsToSaveDeclaredGlobals],
-      context.nativeStorage,
-      globalIds
-    ),
-    create.expressionStatement(globalIds.lastStatementResult)
+  const newStatements = [
+    ...getDeclarationsToAccessTranspilerInternals(globalIds),
+    evallerReplacer(globalIds),
+    create.expressionStatement(create.identifier('undefined')),
+    ...statements
   ]
 
-  program.body = [...getDeclarationsToAccessTranspilerInternals(globalIds), ...body]
+  program.body =
+    context.nativeStorage.evaller === null
+      ? [wrapWithBuiltins(newStatements, context.nativeStorage, globalIds)]
+      : [create.blockStatement(newStatements)]
 
   const map = new SourceMapGenerator({ file: 'source' })
   const transpiled = modulePrefix + generate(program, { sourceMap: map })
   const codeMap = map.toJSON()
-  return { transpiled, codeMap, evalMap }
+  return { transpiled, codeMap }
 }
 
 function getDeclarationsToAccessTranspilerInternals(
@@ -764,12 +565,9 @@ function getDeclarationsToAccessTranspilerInternals(
 ): es.VariableDeclaration[] {
   return Object.entries(globalIds).map(([key, { name }]) => {
     let value: es.Expression
-    let kind: AllowedDeclarations = 'const'
+    const kind: AllowedDeclarations = 'const'
     if (key === 'native') {
       value = create.identifier(NATIVE_STORAGE_ID)
-    } else if (key === 'lastStatementResult') {
-      value = create.primitive(undefined)
-      kind = 'let'
     } else if (key === 'globals') {
       value = create.memberExpression(globalIds.native, 'globals')
     } else {
diff --git a/src/types.ts b/src/types.ts
index a21b1a9b8..da7aa3d91 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -78,16 +78,18 @@ export interface ConstWrapper {
   getValue: () => Value
 }
 
-export interface Globals {
-  variables: Map<string, ValueWrapper>
-  previousScope: Globals | null
-}
-
 export interface NativeStorage {
-  globals: Globals | null
+  builtins: Map<string, Value>
+  previousProgramsIdentifiers: Set<string>
   operators: Map<string, (...operands: Value[]) => Value>
   gpu: Map<string, (...operands: Value[]) => Value>
   maxExecTime: number
+  evaller: null | ((program: string) => Value)
+  /*
+  the first time evaller is used, it must be used directly like `eval(code)` to inherit
+  surrounding scope, so we cannot set evaller to `eval` directly. subsequent assignments to evaller will
+  close in the surrounding values, so no problem
+   */
 }
 
 export interface Context<T = any> {
diff --git a/src/utils/testing.ts b/src/utils/testing.ts
index 59145e096..85a007474 100644
--- a/src/utils/testing.ts
+++ b/src/utils/testing.ts
@@ -115,9 +115,10 @@ async function testInContext(code: string, options: TestOptions): Promise<TestRe
     const nativeTestContext = createTestContext(options)
     let pretranspiled: string = ''
     let transpiled: string = ''
-    let parsed
-    try {
-      parsed = parse(code, nativeTestContext)!
+    const parsed = parse(code, nativeTestContext)!
+    if (parsed === undefined) {
+      pretranspiled = 'parseError'
+    } else {
       // Mutates program
       switch (options.variant) {
         case 'gpu':
@@ -132,15 +133,11 @@ async function testInContext(code: string, options: TestOptions): Promise<TestRe
       try {
         transpiled = transpile(parsed, nativeTestContext, true).transpiled
         // replace declaration of builtins since they're repetitive
-        transpiled = transpiled.replace(
-          /\n  const \w+ = globals\.(previousScope.)+variables.get\("\w+"\)\.getValue\(\);/g,
-          ''
-        )
+        transpiled = transpiled.replace(/\n  const \w+ = nativeStorage\..*;/g, '')
+        transpiled = transpiled.replace(/\n\s*const \w+ = .*\.operators\..*;/g, '')
       } catch {
         transpiled = 'parseError'
       }
-    } catch {
-      pretranspiled = 'parseError'
     }
     const nativeResult = getTestResult(
       nativeTestContext,
diff --git a/src/utils/uniqueIds.ts b/src/utils/uniqueIds.ts
index 7a8c4bea5..cdeac5e74 100644
--- a/src/utils/uniqueIds.ts
+++ b/src/utils/uniqueIds.ts
@@ -18,15 +18,9 @@ export function getUniqueId(usedIdentifiers: Set<string>, uniqueId = 'unique') {
 }
 
 export function getIdentifiersInNativeStorage(nativeStorage: NativeStorage) {
-  const identifiers = new Set<string>()
-  let variableScope = nativeStorage.globals
-  while (variableScope !== null) {
-    for (const name of variableScope.variables.keys()) {
-      identifiers.add(name)
-    }
-    variableScope = variableScope.previousScope
-  }
-  return identifiers
+  const used = new Set(...nativeStorage.builtins.keys())
+  nativeStorage.previousProgramsIdentifiers.forEach(id => used.add(id))
+  return used
 }
 
 export function getIdentifiersInProgram(program: es.Program) {
diff --git a/src/vm/svml-machine.ts b/src/vm/svml-machine.ts
index e66bc8b6e..e7d75c440 100644
--- a/src/vm/svml-machine.ts
+++ b/src/vm/svml-machine.ts
@@ -1770,7 +1770,7 @@ export function runWithProgram(p: Program, context: Context): any {
   // setup externalBuiltins
   // certain functions are imported from cadet-frontend
   // so import them first every time
-  const externals = context.nativeStorage.globals!.variables
+  const externals = context.nativeStorage.builtins
   if (externals.size > 0) {
     EXTERNAL_PRIMITIVES.forEach(func => extractExternalBuiltin(func, externals))
   }
@@ -1834,5 +1834,5 @@ const externalFunctions = new Map<number, any>()
 function extractExternalBuiltin(func: [string, number], externals: Map<string, any>) {
   const name = func[0]
   const opcode = func[1]
-  externalFunctions.set(opcode, externals.get(name).getValue())
+  externalFunctions.set(opcode, externals.get(name))
 }