-- Try running in bare environment to catch any order-dependence in
-- definitions. The basic intent is to avoid this situation:
-- define X = 3
-- define Y = X+1
-- edit X = 4
-- Now the definition of Y runs before X (because Freewheeling apps load
-- top-level definitions in version order) when X is nil, and Y starts
-- raising a confusing error. And all because we modified X. Action at a
-- distance.
--
-- To avoid this we make sure each definition is always self-contained.
--
-- This feels highly experimental. Concerns:
--
-- 1. Any side-effects in top-level definitions will run twice. Ugh.
-- But then, they will also run any time you restart the app.
-- Putting side-effects in the top-level seems like a more unnatural thing
-- for a programmer to do than defining one global in terms of another.
--
-- 2. We still won't catch situations where we depended on a global
-- variable and it used to be non-nil but now it's nil:
-- define X = 3
-- define Y = X
-- edit X = 4
-- Now Y is nil when it didn't used to be. Which can be confusing. And it
-- won't even raise any errors.
--
-- 3. I'm going to create only a shallow copy of globals. It's hard to
-- think about what real, really humongous global variables we might end
-- up accidentally copying and turning everything sluggish. We might still
-- miss some situation like:
-- define io.bar
-- define Y = io.bar -- allowed because io.bar has leaked in to the bare environment
-- So this isn't perfect.
--
-- 4. Lua's setfenv is confusing to me. I wonder if there's some situation
-- like:
-- X = foo()
-- that might cause trouble because foo() will continue to use the
-- non-initial environment.
--
-- So far it seems fine. My intent is only to catch order-dependence in
-- top-level definitions. The initial environment will have a subset of
-- definitions; we prevent the live app from mutating any of them. It seems
-- reasonable to assume that any pre-existing functions will not rely on any
-- globals some random app is going to introduce.
--
-- 5. I could probably move the setfenv into eval_in_initial_env, but that
-- feels confusing to think about given the table of bar envs is itself
-- stored in a global variable.
--
-- 6. I could probably avoid duplicating eval as eval_in_initial_env, but
-- it feels less error-prone to keep the two isolated. We never mess with
-- the env of the real eval.
setfenv(live.eval_in_initial_env, table.copy(Live.initial_env))
local status, err = live.eval_in_initial_env(buf)
if not status then
live.roll_back()
live.send_to_driver('ERROR this definition depends on other globals which can lead to hard-to-debug errors. Please keep top-level definitions order-independent. Define functions for more complex initialization.')
return
end