Module: dfmc-flow-graph Author: Jonathan Bachrach Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND //// Variables // TODO: Work out which of these should and can be abstract and which // concrete. define /* abstract */ class (, , ) end class; define method rest-variable? (var :: ) #f end method; define method keyword-variable? (var :: ) #f end method; define class () slot specializer, required-init-keyword: specializer:; end class; // !@#$ super hack -- happens on rest parameters define method specializer (object) dylan-value(#"") end; define class () end class; define class () end class; define /* abstract */ class () end class; define class () end class; define method rest-variable? (variable :: ) #t end method; define class () end class; define method keyword-variable? (variable :: ) #t end method; //// Environments define sideways method frame-size (env :: ) => (size :: ) 0 end; define sideways method frame-size-setter (value, env :: ) 0 end; define method outer (environment :: ) #f end method; define class () slot outer :: false-or(), required-init-keyword: outer:; // slot cached-lexical-variables-in-scope = #f; end class; define inline method top-level-environment? (env :: ) ~outer(env) end method; /// TODO: THIS HACK WILL ONLY WORK UNTIL WE USE LIMITED VECTORS OF TMPS define constant $weak-temporaries = as(, #[#"weak"]); define inline function weak-temporaries? (tmps :: ) => (well? :: ) size(tmps) = 1 & tmps[0] == #"weak" end function; define dood-class () slot lambda :: false-or(<&lambda>), required-init-keyword: lambda:; weak slot temporaries :: = make(), reinit-expression: $weak-temporaries; // slot temporaries :: = make(); slot rare-environment-data :: = #[]; end dood-class; define method ensure-lambda-body (fun :: <&lambda>) => () let env = environment(fun); when (env & weak-temporaries?(temporaries(env))) for-all-lambdas (lambda in fun) let env = environment(lambda); temporaries(env) := compute-temporaries(env); end for-all-lambdas; end when; end method; define method approximate-number-temporaries (fun :: <&lambda>) => (res :: ) 2 ^ lambda-log-number-temporaries(fun) end method; define method compute-temporaries (env :: ) => (res :: ) let fun = lambda(env); let tmps = make(, capacity: approximate-number-temporaries(fun)); for (parameter in parameters(fun)) environment(parameter) := env; add!(tmps, parameter) end for; frame-size(env) := size(tmps); local method maybe-add-temporary! (c :: , tmp :: false-or()) when (tmp) generator(tmp) := c; environment(tmp) := env; frame-offset(tmp) := next-frame-offset(env); add!(tmps, tmp) end when; end method; for-computations (c :: previous pc :: false-or() in fun) environment(c) := env; previous-computation(c) := pc; maybe-add-temporary!(c, temporary(c)); when (instance?(c, )) maybe-add-temporary!(c, entry-state(c)); end when; end for-computations; tmps end method; define class () end class; define method compute-temporaries (env :: ) => (res :: ) make() end method; define method number-temporaries (e :: ) => (res :: ) size(temporaries(e)) end method; define inline method clear-temporaries! (env :: ) size(env.temporaries) := 0; end method; define inline method remove-temporary! (env :: , t :: ) remove!(env.temporaries, t) end method; define inline method add-temporary! (env :: , t :: ) add!(env.temporaries, t) end method; define sealed inline method initialize (x :: , #key, #all-keys) next-method(); bindings(x) := make(); end method; define rare-slots (, rare-environment-data) slot bindings :: false-or() = #f; slot variable-assignments :: false-or() = #f; slot inners :: = #(); // FOR NESTED LAMBDAS slot entries :: = #(); // FOR BLOCKS slot loops :: = #(); // FOR LOOP CONVERSION slot closure :: = #(); // FOR CLOSED OVER TEMPORARIES slot lifture :: = #(); // FOR LIFTED CLOSED OVER TEMPORARIES end rare-slots; ignore(remove-inners!); ignore(remove-lifture!); define method strip-bindings (env :: ) remove-bindings!(env); end method; define method strip-assignments (env :: ) remove-variable-assignments!(env); end method; // define method broken (s, #rest a) // // apply(break, s, a); // end method; define method strip-environment (env :: ) strip-bindings(env); strip-assignments(env); remove-entries!(env); remove-loops!(env); let number-temporaries = size(temporaries(env)); lambda-log-number-temporaries(lambda(env)) := if (number-temporaries = 0) 0 else round/(log(as(, number-temporaries)), log(2.0)) end if; /* let tmps* = compute-temporaries(env); let tmps = temporaries(env); unless (size(tmps*) = size(tmps)) for (tmp in tmps) when (used?(tmp) & ~member?(tmp, tmps*)) format-out("IN %= RECONSTRUCTED TEMPORARIES %= INVALID %= MISSING %=\n", lambda(env), tmps*, tmps, tmp); broken("BAD RECONSTRUCTION %= %=", lambda(env), tmp); end when; end for; end unless; */ end method; define method assignments (tmp :: ) => (res :: ) let tbl = variable-assignments(environment(tmp)); if (tbl) element(tbl, tmp, default: #()) else #() end if; end method; define method assignments-setter (value :: , tmp :: ) => (res :: ) let tbl ::
= variable-assignments(environment(tmp)) | (variable-assignments(environment(tmp)) := make(
)); if (value == #()) remove-key!(tbl, tmp); value else element(tbl, tmp) := value; end if; end method; define method frame-size (env :: ) => (res :: ) number-temporaries(env) end method; define method frame-size-setter (new-value, env :: ) end method; define method lambda-loop (f :: <&lambda>) => (res) first(f.environment.loops, default: #f) end method; define method lambda-loop-setter (loop, f :: <&lambda>) let env = f.environment; // TODO: MANAGE THESE // env.loops := add!(env.loops, loop); env.loops := list(loop); end method; define constant $top-level-environment = make(, lambda: #f, outer: #f); define method lambda-environment (env :: ) env end; define method add-inner! (env :: , inner :: ) end method; define method add-inner! (env :: , inner :: ) end method; define method add-inner! (env :: , inner :: ) env.inners := add-new!(env.inners, inner); end method; define class () constant slot binding-id, required-init-keyword: id:; constant slot binding-type, required-init-keyword: type:; constant slot binding-value, required-init-keyword: value:; // SAVE SLOTS // slot %lambda-environment :: false-or() = #f, // init-keyword: environment:; end class; define function make-local-lexical-environment (name :: , value, type, env :: ) => (new-env :: ) make(, id: name, type: type, value: value, outer: env) end; define method lambda-environment (env :: ) lambda-environment(outer(env)) end; /* SAVE SLOTS define method lambda-environment (env :: ) %lambda-environment(env) | (%lambda-environment(env) := lambda-environment(outer(env))) end; define method lambda-environment-setter (value :: , env :: ) %lambda-environment(env) := value; end; */ define method add-inner! (env :: , inner :: ) add-inner!(env.outer, inner) end method; define method all-environments (environment :: ) collecting () iterate loop (environment = environment) collect(environment); if (environment.outer) loop(environment.outer); end if; end iterate; end collecting; end method; define method next-frame-offset (env :: ) let offset = env.frame-size; env.frame-size := env.frame-size + 1; offset end method; define method add-variable! (env :: , name :: , variable :: ) env.bindings[name] := variable; end method; define method lookup (env :: , name :: , #rest options, #key default, reference? = #t) => (binding, type, environment) let v = element(env.bindings, name, default: #f); if (v) values(v, #f, env) else apply(lookup, env.outer, name, options) end end method; define method lookup (env :: , name :: , #rest options, #key default, reference? = #t) => (binding, type, environment) if (same-name-when-local?(binding-id(env), name)) values(binding-value(env), binding-type(env), env) else apply(lookup, env.outer, name, options) end end method; define function lookup-in-top-level-environment (name :: , default, reference?) => (binding, type, environment) let env = outer-lexical-environment(); let val = if (env) element(env, name, default: not-found()) else not-found() end; if (found?(val)) values(make(, name: name, interactor-id: val), #f, #f); // TODO: Remove the following clause - for testing only. // elseif (member?(fragment-name(name), #(#"$$interactive"))) // make(, name: name, interactor-id: val); else values(lookup-binding(name, reference?: reference?), #f, #f) end; end; define method lookup (env == #f, name :: , #key default, reference? = #t) => (binding, type, environment) lookup-in-top-level-environment(name, default, reference?) end method; define method lookup (env :: , name :: , #key default, reference? = #t) => (binding, type, environment) lookup-in-top-level-environment(name, default, reference?) end method; define method inner-environment? (maybe-inner :: , maybe-outer :: ) block (return) for (e = maybe-inner then e.outer, while: e) if (e == maybe-outer) return(#t); end if; finally #f end for end block end method inner-environment?; define generic lambda-has-free-lexical-references? (object :: <&lambda-or-code>) => (free-references? :: ); define function closure-self-reference? (t :: , lambda-env :: ) => (res :: ) let c = generator(t); instance?(c, ) & lambda-env == environment(computation-closure-method(c)) end function; define function closure-self-referencing? (lambda-env :: ) => (res :: ) any?(rcurry(closure-self-reference?, lambda-env), closure(lambda-env)) end function; define method lambda-has-free-lexical-references? (lambda :: <&lambda>) => (free-references? :: ) // look upward, since we know there isn't much that way -- // this is only used for , which only occurs at "top level" // if this is ever called from elsewhere, it may need to get cleverer to // be sufficiently fast let lambda-env = environment(lambda); block (found) for (outer-env = outer(lambda-env) then outer(outer-env), while: outer-env) if (instance?(outer-env, )) for-temporary (t in outer-env) for (use in users(t)) if (inner-environment?(environment(use), lambda-env)) // some use of an outer temporary is inside this lambda found(#t) end; end; end; end; end; #f end; end; define method lambda-has-free-lexical-references? (code :: <&code>) => (free-references? :: ) lambda-has-free-lexical-references?(function(code)) end; define method extract-lambda (lambda :: <&lambda>) => () // splice lambda out of the outer lambda // must be known to have no free lexical references // XXX: might violation of this precondition lead to the // mysterious "are live on entry to lambda" errors? let env = environment(lambda); let outer-env = lambda-environment(outer(env)); let outer-outer-env = outer(outer-env); inners(outer-env) := remove!(inners(outer-env), env); outer(env) := outer-outer-env; if (outer-outer-env) add-inner!(lambda-environment(outer-outer-env), env); end; lambda-top-level?(lambda) := #t; run-compilation-passes(lambda); end; define method extract-lambda (code :: <&code>) => () extract-lambda(function(code)) end; // Walk the lexical variables of the environment in inside out order. // define generic do-lexical-variables-in-scope // (f :: , env :: false-or()) => (); // // define method do-lexical-variables-in-scope // (f :: , env == #f) => () // end method; // // define method do-lexical-variables-in-scope // (f :: , env :: ) => () // end method; // // define method do-lexical-variables-in-scope // (f :: , env :: ) => () // do-lexical-variables-in-scope(f, env.outer); // end method; // // define method do-lexical-variables-in-scope // (f :: , env :: ) => () // for (var in env.bindings) f(var) end; // next-method(); // end method; // // define method do-lexical-variables-in-scope // (f :: , env :: ) => () // f(binding-value(env)); // next-method(); // end method; // // define method lexical-variables-in-scope // (env :: ) => (variables :: ) // env.cached-lexical-variables-in-scope // | (env.cached-lexical-variables-in-scope // := collecting () // do-lexical-variables-in-scope(method (var) collect(var) end, env); // end); // end method; // Hacks!!! define sideways method classify-word-in (context :: , word) classify-word-in(tail(context), word); end method; define sideways method fragment-module (form :: ) => (module :: ) let module = fragment-context(form); if (module) if (instance?(module, )) // Local environment + module. tail(module); else module end; else dylan-implementation-module(); end; end method; // eof